首页 > 代码库 > bzoj3637 CodeChef SPOJ - QTREE6 Query on a tree VI 题解

bzoj3637 CodeChef SPOJ - QTREE6 Query on a tree VI 题解

题意:

  一棵n个节点的树,节点有黑白两种颜色,初始均为白色。两种操作:1.更改一个节点的颜色;2.询问一个节点所处的颜色相同的联通块的大小。

思路:

  1.每个节点记录仅考虑其子树时,假设其为黑色时所处的黑色联通块的大小和假设其为白色时所处的白色联通块的大小(树状数组维护)。
  2.查询时找到深度最小的、与该点颜色相同的且两点之间的点颜色均与这两点相同(两点可以重合)(不妨称它为最远祖先)的答案。
  3.修改时应该修改该节点的父亲至最远祖先的父亲上的值。
  4.用树链剖分和树状数组维护。
  5.寻找最远祖先时,跳重链,树状数组维护当前颜色(0为白 1为黑),查询重链上的颜色和,判断是否整段相同。是则继续向上跳,否则二分祖先。

反思:

  1.越上面的dfn越小,二分开始打反了(二分看了Po姐的)
  2.树链剖分有些生疏,开始时打错死循了。树状数组的应用不熟练。
  3.开始时修改时是边找最远祖先边修改的,结果在根周围时出现了问题。
  4.根在修改、查询时都特判一下,重链的端点为最远祖先时也特判一下。

代码:

 1 #include<cstdio>
 2 #define M 100005
 3 #define swap(x,y) u=x,x=y,y=u
 4 int n,u,cnt,dfn,p[M],v[M<<1],id[M],co[M],sz[M],di[M],dep[M],top[M],hea[M],nex[M<<1],ans[M][2];
 5 bool col[M];
 6 
 7 void ins(int x,int y) { v[++cnt]=y,nex[cnt]=hea[x],hea[x]=cnt; }
 8 void Add(int x,int y) { for (;x<=n;x+=x&-x) co[x]+=y; }
 9 int Ask(int x) { int s=0; for (;x;x-=x&-x) s=s+co[x]; return s; }
10 void add(int x,int y,bool c) { for (;x<=n;x+=x&-x) ans[x][c]+=y; }
11 int ask(int x,bool c) { int s=0; for (;x;x-=x&-x) s=s+ans[x][c];  return s;}
12 bool pd(int x,int y,bool c)
13 { return c && (Ask(y)-Ask(x-1))==(y-x+1) || (!c) && (Ask(x-1)==Ask(y)); }
14 int read()
15 {
16     int x=0; char ch=getchar();
17     for (;ch<48 || ch>57;ch=getchar());
18     for (;ch>47 && ch<58;ch=getchar()) x=(x<<1)+(x<<3)+ch-48;
19     return x;
20 }
21 
22 void dfs(int x)
23 {
24     sz[x]=1;
25     for (int i=hea[x],y;i;i=nex[i])
26         if ((y=v[i])^p[x]) p[y]=x,dep[y]=dep[x]+1,dfs(y),sz[x]+=sz[y];
27 }
28 
29 void dfs(int x,int chain)
30 {
31     int i,k=0,y;
32     top[x]=chain,id[x]=++dfn,di[dfn]=x;
33     for (i=hea[x];i;i=nex[i])
34         if ((y=v[i])^p[x] && sz[y]>sz[k]) k=y;
35     if (!k) return; dfs(k,chain);
36     for (i=hea[x];i;i=nex[i])
37         if ((y=v[i])^p[x] && y^k) dfs(y,y);
38 }
39 
40 void change(int x,int y,int v,bool c)
41 {
42     for (;top[x]!=top[y];x=p[top[x]])
43     {
44         if (dep[top[x]]<dep[top[y]]) swap(x,y);
45         add(id[top[x]],v,c),add(id[x]+1,-v,c);
46     }
47     if (dep[x]<dep[y]) swap(x,y);
48     add(id[y],v,c),add(id[x]+1,-v,c);
49 }
50 
51 int find(int x,bool c)
52 {
53     int l,r,t,y,mid;
54     for (;x^1;x=p[y])
55     {
56         l=id[y=top[x]],t=r=id[x];
57         if (!pd(l,r,c))
58         {
59             while (l+1<r)
60                 if (pd((mid=(l+r)>>1),t,c)) r=mid; else l=mid+1;
61             if (pd(l,t,c)) return l; return r;
62         }
63         if (col[p[y]]^c) return l;
64     }
65     return 1;
66 }
67 
68 int main()
69 {
70     n=read(); int i,x,y,m;
71     for (i=1;i<n;++i) x=read(),y=read(),ins(x,y),ins(y,x);
72     dfs(p[1]=1),dfs(1,1),add(1,1,1);
73     for (i=1;i<=n;++i) add(id[i],sz[i],0),add(id[i]+1,-sz[i],0);
74     for (m=read();m--;)
75     {
76         i=read(),x=read();
77         if (i)
78         {
79             i=col[x];if (x-1) change(p[x],p[di[find(x,i)]],-ask(id[x],i),i);
80             if (i) Add(id[x],-1); else Add(id[x],1); col[x]^=1;
81             i=col[x];if (x-1) change(p[x],p[di[find(x,i)]],ask(id[x],i),i);
82         }
83         else i=col[x],printf("%d\n",ask(find(x,i),i));
84     }
85     return 0;
86 }

 

bzoj3637 CodeChef SPOJ - QTREE6 Query on a tree VI 题解