【树链剖分】春季大扫除(P6805)
生活随笔
收集整理的這篇文章主要介紹了
【树链剖分】春季大扫除(P6805)
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
正題
P6805
題目大意
給你一棵樹,每次可選擇兩個葉子結(jié)點,然后覆蓋路徑上的邊,代價為其長度,每個葉子結(jié)點只能選一次。
對于每次詢問,加入若干新點(只會連接原樹的點),問你覆蓋所有邊的最小代價。
解題思路
因為所有邊都要覆蓋,所以一個點至少連一條到父親的邊
不難發(fā)現(xiàn),如果一個點的子樹內(nèi)有偶數(shù)各葉子結(jié)點,那么就要連出兩條邊,否則連一條邊,因為所有點都要連向父親,所以只計算多出來的
那么可以樹鏈剖分,然后用線段樹維護子樹葉子結(jié)點的值
對于每次查詢,相當(dāng)于把若干鏈上的值異或1,然后查詢整棵樹的值
code
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define ll long long #define N 100100 using namespace std; int n,m,q,x,y,w,tot,a[N],s[N],h[N],p[N]; int sz[N],fa[N],hs[N],deg[N],low[N],dfn[N],dep[N],top[N],lsz[N]; struct rec {int to,nx; }e[N<<1]; void add(int x,int y) {e[++tot].to=y;e[tot].nx=h[x];h[x]=tot;return; } struct Tree {#define ls x*2#define rs x*2+1int v[N<<2],lazy[N<<2];void push_up(int x){v[x]=v[ls]+v[rs];return;}void get(int x,int l,int r){lazy[x]^=1;v[x]=r-l+1-v[x];return;}void push_down(int x,int l,int r){if(lazy[x]){int mid=l+r>>1;get(ls,l,mid);get(rs,mid+1,r);lazy[x]=0;}return;}void change(int x,int L,int R,int l,int r){if(L==l&&R==r){get(x,L,R);return;}push_down(x,L,R);int mid=L+R>>1;if(r<=mid)change(ls,L,mid,l,r);else if(l>mid)change(rs,mid+1,R,l,r);else change(ls,L,mid,l,mid),change(rs,mid+1,R,mid+1,r);push_up(x);return;}int ask(int x,int L,int R,int l,int r){if(L==l&&R==r)return v[x];push_down(x,L,R);int mid=L+R>>1;if(r<=mid)return ask(ls,L,mid,l,r);else if(l>mid)return ask(rs,mid+1,R,l,r);else return ask(ls,L,mid,l,mid)+ask(rs,mid+1,R,mid+1,r);} }T; void dfs1(int x) {sz[x]=1;if(deg[x]==1)lsz[x]=1,p[x]=1;for(int i=h[x];i;i=e[i].nx){int y=e[i].to;if(y==fa[x])continue;fa[y]=x;dep[y]=dep[x]+1;dfs1(y);sz[x]+=sz[y];lsz[x]+=lsz[y];if(sz[y]>sz[hs[x]])hs[x]=y;}return; } void dfs2(int x,int anc) {dfn[x]=++w;top[x]=anc;if(!(lsz[x]&1))T.change(1,1,n,dfn[x],dfn[x]);if(hs[x])dfs2(hs[x],anc);for(int i=h[x];i;i=e[i].nx){int y=e[i].to;if(y==fa[x]||y==hs[x])continue;dfs2(y,y);}low[x]=w;return; } void add(int x) {while(top[x]!=1){T.change(1,1,n,dfn[top[x]],dfn[x]);x=fa[top[x]];}T.change(1,1,n,dfn[1],dfn[x]);return; } int main() {scanf("%d%d",&n,&q);for(int i=1;i<n;++i){scanf("%d%d",&x,&y);add(x,y);add(y,x);deg[x]++;deg[y]++;}dep[1]=fa[1]=1;dfs1(1);dfs2(1,1);while(q--){scanf("%d",&m);for(int i=1;i<=m;++i){scanf("%d",&a[i]);s[i]=1;}a[m+1]=0;sort(a+1,a+1+m);for(int i=1;i<=m;++i)if(a[i]==a[i+1])s[i+1]+=s[i];else if(p[a[i]]){if(!(s[i]&1))add(a[i]);//修改一條鏈}else if(s[i]&1)add(a[i]);if(!T.ask(1,1,n,dfn[1],dfn[1]))puts("-1");//無法兩兩匹配else printf("%d\n",T.ask(1,1,n,dfn[1],low[1])+n+m-2);//加上沒算的邊,1沒有連向父親的邊,但兩邊都會多算一次for(int i=1;i<=m;++i)if(a[i]!=a[i+1]){if(p[a[i]]){if(!(s[i]&1))add(a[i]);}else if(s[i]&1)add(a[i]);}}return 0; }總結(jié)
以上是生活随笔為你收集整理的【树链剖分】春季大扫除(P6805)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【树链剖分】洛谷树(P3401)
- 下一篇: lol最高配置(lol高配置电脑配置)