SPOJ QTREE Query on a tree VI
You are given a tree (an acyclic undirected connected graph) with n nodes. The tree nodes are numbered from 1 to n. Each node has a color, white or black. All the nodes are black initially. We will ask you to perform some instructions of the following form:
- 0 u: ask for how many nodes are connected to u, two nodes are connected if all the node on the path from u to v (inclusive u and v) have the same color.
- 1 u: toggle the color of u (that is, from black to white, or from white to black).
Input
The first line contains a number n that denotes the number of nodes in the tree (1 ≤ n ≤ 105). In each of the following n-1 lines, there will be two numbers (u, v) that describes an edge of the tree (1 ≤ u, v ≤ n). The next line contains a numberm denoting number of operations we are going to process (1 ≤ m ≤ 105). Each of the following m lines describe an operation (t, u) as we mentioned above(0 ≤ t ≤ 1, 1 ≤ u ≤ n).
Output
For each query operation, output the corresponding result.
Example
Input 1:
5 1 2 1 3 1 4 1 5 3 0 1 1 1 0 1 Output 1:
5 1
Input 2:
7 1 2 1 3 2 4 2 5 3 6 3 7 4 0 1 1 1 0 2 0 3
Output 2:
7 3 3
Warning: large input/output data,be careful with certain languages
改变某个点的颜色,或者询问与某点相连(两点路径上没有异色点)的同色点有多少个
树 树链剖分+树状数组
首先需要一个方便的统计答案的方式。每个点开一个统计答案的变量,显然可行,但是更新麻烦。
考虑把一整块儿同色点的答案存储在它们中深度最浅的那个点上。若如此做,修改一个点的颜色时,只需要修改从该点到根的一条链上的答案。
如果有了树剖,存储答案就可以用线段树或者树状数组。听说线段树容易T,那就用树状数组咯。
修改一个点时,先找到从该点向上的最长同色链,整链减去答案,再改变颜色,再找到从该点向上的最长同色链,整链累加答案。
如何找最长同色链?
另开一个树状数组,记录链上某颜色点的数量的前缀和。如果整条重链上的某颜色点数量等于链长度,显然可以尝试继续上溯,否则说明同色链的最浅点在当前重链上,那么就在当前重链上二分判断。
如何记录答案?
脑洞了各种方法,最后发现比较方便的改法是,修改x的father到最浅点的father这条链(在前者上减去,在后者上累加),因为x上要存x以下的连通块的答案,方便颜色变回来时的累加,所以不能改。作为等价调整,需要在x的father上减。(类比DFS序问题的值维护)
无数次WA和RE,过程中重构了两次代码,无尽的debug。写这一道题花了近一整天时间。
前两份代码中,为了树状数组操作方便,树剖出的结点编号是倒着编号的。然而这样似乎在向下修改子结点时下标会出现0,使得树状数组爆炸。
最后借鉴别人的二分方式,并改成了正序编号,迷之解决了迷之问题
还有其他各种各样的毛病……
顺带一提,最后两小时时间找出的bug,是某一句调用树状数组的时候,把pos和co的位置写反了……
信心尽失,痛不欲生,好在最后还是过了。
1 /*by SilverN*/ 2 #include<algorithm> 3 #include<iostream> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 using namespace std; 8 const int INF=1e8; 9 const int mxn=200010; 10 int read(){ 11 int x=0,f=1;char ch=getchar(); 12 while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} 13 while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} 14 return x*f; 15 } 16 struct edge{int v,nxt;}e[mxn<<1]; 17 int hd[mxn],mct=0; 18 void add_edge(int u,int v){ 19 e[++mct].v=v;e[mct].nxt=hd[u];hd[u]=mct;return; 20 } 21 int n,m; 22 // 23 int ct[4][mxn]; 24 int col[mxn]; 25 void add(int p,int co,int v){ 26 while(p<=n){ct[co][p]+=v;p+=p&-p;} 27 return; 28 } 29 int ask(int co,int p){ 30 int res=0; 31 while(p){res+=ct[co][p];p-=p&-p;} 32 return res; 33 } 34 // 35 struct node{ 36 int fa,son,top;int sz,w,e; 37 }t[mxn]; 38 int dep[mxn]; 39 int id[mxn],cnt=0; 40 void DFS1(int u,int fa){ 41 t[u].sz=1;dep[u]=dep[fa]+1; 42 for(int i=hd[u];i;i=e[i].nxt){ 43 if(e[i].v==fa)continue;int v=e[i].v; 44 t[v].fa=u; 45 DFS1(v,u); 46 t[u].sz+=t[v].sz; 47 if(t[v].sz>t[t[u].son].sz)t[u].son=v; 48 } 49 return; 50 } 51 void DFS2(int u,int top){ 52 t[u].w=++cnt;t[u].top=top; 53 id[cnt]=u; 54 if(t[u].son){ 55 DFS2(t[u].son,top); 56 for(int i=hd[u];i;i=e[i].nxt){ 57 if(e[i].v==t[u].fa || e[i].v==t[u].son)continue; 58 DFS2(e[i].v,e[i].v); 59 } 60 } 61 t[u].e=cnt; 62 } 63 // 64 int find(int L,int R,int co){//链上查询相连的同色最浅点 65 int l=L,r=R,ans=0; 66 while(r<=l){//左边深右边浅 67 int mid=(l+r)>>1; 68 int res=ask(co,l)-ask(co,mid-1); 69 if(res==l-mid+1){ 70 ans=mid;l=mid-1; 71 }else r=mid+1; 72 } 73 return ans; 74 } 75 int query(int x){//查询从x到y的链上的连续同色最浅点的树剖编号 76 int cc=col[x]; 77 while(t[x].top!=1){ 78 int tmp=ask(cc,t[x].w)-ask(cc,t[t[x].top].w-1); 79 if(tmp==t[x].w-t[t[x].top].w+1){ 80 if(col[x]!=col[t[t[x].top].fa])return t[t[x].top].w; 81 else x=t[t[x].top].fa; 82 } 83 else return find(t[x].w,t[t[x].top].w,cc); 84 } 85 return find(t[x].w,t[1].w,cc); 86 } 87 void upd(int x,int y,int v,int c){ 88 while(t[x].top!=t[y].top){ 89 if(dep[t[x].top]<dep[t[y].top])swap(x,y); 90 add(t[t[x].top].w,c,v); 91 add(t[x].w+1,c,-v); 92 x=t[t[x].top].fa; 93 } 94 if(dep[x]>dep[y])swap(x,y); 95 add(t[x].w,c,v); 96 add(t[y].w+1,c,-v); 97 return; 98 } 99 void update(int x){ 100 int y=id[query(x)]; 101 if(x>1)upd(t[y].fa,t[x].fa,-ask(col[x]+2,t[x].w),col[x]+2); 102 add(t[x].w,col[x],-1); 103 col[x]^=1; 104 add(t[x].w,col[x],1); 105 y=id[query(x)]; 106 if(x>1)upd(t[y].fa,t[x].fa,ask(col[x]+2,t[x].w),col[x]+2); 107 return; 108 } 109 int main(){ 110 // freopen("in.txt","r",stdin); 111 int i,j,u,v; 112 n=read(); 113 for(i=1;i<n;i++){ 114 u=read();v=read(); 115 add_edge(u,v); 116 add_edge(v,u); 117 } 118 DFS1(1,1);t[1].fa=1;// 119 // cnt=n+1; 120 DFS2(1,1); 121 for(i=1;i<=n;i++){//初始化,全为黑色 122 col[i]=1; 123 add(t[i].w,col[i]+2,t[i].sz); 124 add(t[i].w+1,col[i]+2,-t[i].sz); 125 add(t[i].w,col[i],1); 126 } 127 add(1,2,1); 128 m=read();int op,x; 129 while(m--){ 130 op=read();x=read(); 131 if(op){//修改 132 update(x); 133 } 134 else{//查询 135 int y=id[query(x)]; 136 int ans=ask(col[x]+2,t[y].w); 137 printf("%d\n",ans); 138 } 139 } 140 return 0; 141 }