[CodeChef-QTREE6]Query on a tree VI
题目大意:
给你一棵黑白树,每个点默认是白色,要求支持以下两种操作:
1.改变一个点的颜色;
2.除去连接不同颜色的点的边,求某个点连通块的大小。
思路:
对原树维护两个树链剖分,
一棵维护当点x为白色时,以它为根结点的白色的子树大小;
另一棵维护当点x为黑色时,以它为根结点的黑色的子树大小。(两者均不考虑x的实际颜色)
方便起见,这里我们用q表示同一个连通分量中,深度最浅的祖先。
询问一个点时,相当于在询问q的值。
修改一个点时,相当于在原来颜色的树剖上将x到q的路径上的所有点同时减去x同色子树的大小,然后在新的颜色的树剖上将x到q路径上的所有点同时加上x同色子树的大小。
如果对每个点都加/减显然不方便,因此我们可以用一些数据结构(线段树/树状数组)来维护差分。
注意这道题会卡常,要么对每一条链建线段树,要么就用树状数组。
接下来的问题是如何找到祖先q。
如果暴力往上找,时间复杂度是O(n)的,显然会TLE。
假如我们能够直接判断某一个树链上的点是否是同一种颜色,那就可以直接往上跳了。
如何直接判断?
考虑用0代表白色,1代表黑色,如果当这条链上所有点的权值和等于这条链上结点的个数,或等于0,那么肯定是同一种颜色的。
这样我们可以直接维护树上前缀和,询问的时候减一下就可以了。
最后还剩半条链没法跳的时候可以二分中间的结点。
1 #include<cstdio> 2 #include<cctype> 3 #include<vector> 4 inline int getint() { 5 char ch; 6 while(!isdigit(ch=getchar())); 7 int x=ch^'0'; 8 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 9 return x; 10 } 11 const int V=100001; 12 std::vector<int> e[V]; 13 inline void add_edge(const int &u,const int &v) { 14 e[u].push_back(v); 15 } 16 int par[V],size[V],son[V],top[V],id[V],dep[V],id2[V],n; 17 bool col[V]; 18 void dfs1(const int &x,const int &p) { 19 par[x]=p; 20 size[x]=1; 21 dep[x]=dep[p]+1; 22 for(unsigned i=0;i<e[x].size();i++) { 23 const int &y=e[x][i]; 24 if(y==p) continue; 25 dfs1(y,x); 26 size[x]+=size[y]; 27 if(size[y]>size[son[x]]) { 28 son[x]=y; 29 } 30 } 31 } 32 void dfs2(const int &x) { 33 id[x]=++n; 34 id2[n]=x; 35 top[x]=x==son[par[x]]?top[par[x]]:x; 36 if(son[x]) dfs2(son[x]); 37 for(unsigned i=0;i<e[x].size();i++) { 38 const int &y=e[x][i]; 39 if(y==par[x]||y==son[x]) continue; 40 dfs2(y); 41 } 42 } 43 class FenwickTree { 44 private: 45 int val[V]; 46 int lowbit(const int &x) { 47 return x&-x; 48 } 49 public: 50 void modify(int p,const int &x) { 51 while(p<=n) { 52 val[p]+=x; 53 p+=lowbit(p); 54 } 55 } 56 int query(int p) { 57 int ret=0; 58 while(p) { 59 ret+=val[p]; 60 p-=lowbit(p); 61 } 62 return ret; 63 } 64 }; 65 FenwickTree t[3]; 66 bool check(const int &u,const int &m) { 67 return t[2].query(id[u])-t[2].query(id[m]-1)==col[u]*(dep[u]-dep[m]+1); 68 } 69 inline int get_anc(int u) { 70 while(top[u]!=1&&check(u,top[u])) { 71 if(col[par[top[u]]]==col[u]) { 72 u=par[top[u]]; 73 } else { 74 return top[u]; 75 } 76 } 77 int l=id[top[u]],r=id[u]; 78 while(l<=r) { 79 const int mid=(l+r)>>1; 80 if(check(u,id2[mid])) { 81 r=mid-1; 82 } else { 83 l=mid+1; 84 } 85 } 86 return id2[r+1]; 87 } 88 inline void modify2(int x,int y,const int &k,const bool &c) { 89 while(top[x]!=top[y]) { 90 t[c].modify(id[top[x]],k); 91 t[c].modify(id[x]+1,-k); 92 x=par[top[x]]; 93 } 94 t[c].modify(id[y],k); 95 t[c].modify(id[x]+1,-k); 96 } 97 inline void modify(const int &u) { 98 if(u!=1) modify2(par[u],par[get_anc(u)],-t[col[u]].query(id[u]),col[u]); 99 t[2].modify(id[u],col[u]?-1:1); 100 col[u]^=true; 101 if(u!=1) modify2(par[u],par[get_anc(u)],t[col[u]].query(id[u]),col[u]); 102 } 103 inline int query(const int &u) { 104 return t[col[u]].query(id[get_anc(u)]); 105 } 106 int main() { 107 int n=getint(); 108 for(register int i=1;i<n;i++) { 109 const int u=getint(),v=getint(); 110 add_edge(u,v); 111 add_edge(v,u); 112 } 113 dfs1(1,1); 114 dfs2(1); 115 for(register int i=1;i<=n;i++) { 116 t[0].modify(id[i],size[i]); 117 t[0].modify(id[i]+1,-size[i]); 118 } 119 t[1].modify(1,1); 120 for(register int m=getint();m;m--) { 121 const int t=getint(),u=getint(); 122 if(t) { 123 modify(u); 124 } else { 125 printf("%d\n",query(u)); 126 } 127 } 128 return 0; 129 }