bzoj4771 七彩树

传送门

不得不说这是道好题……

先考虑没有深度限制的情况,显然把每种颜色的点做一个树链的并,再求一个子树标记和就行了,这个没什么难度。

然后考虑有了深度限制的情况,我们可以按深度从小到大依次加入所有点,对每个深度分别维护一棵线段树存储每个点的标记和,查询(x,d)的时候就在x的深度+d对应的线段树中查询子树标记和即可。不难发现每个深度的线段树都是可以从上一个快速更新得到的,那么就可以可持久化了,每次把当前深度的点加入并更新一下树链的并,因此还需要用set维护前驱后继。

被set坑了好久,感觉一年半的STL都白学了……

  1 /**************************************************************
  2     Problem: 4771
  3     User: hzoier
  4     Language: C++
  5     Result: Accepted
  6     Time:2176 ms
  7     Memory:118204 kb
  8 ****************************************************************/
  9 #include<cstdio>
 10 #include<cstring>
 11 #include<algorithm>
 12 #include<vector>
 13 #include<set>
 14 using namespace std;
 15 const int maxn=100010,maxm=maxn<<6;
 16 void clear(int);
 17 void bfs();
 18 int LCA(int,int);
 19 void build(int,int,int&);
 20 void query(int,int,int);
 21 int copy(int);
 22 int sm[maxm]={0},lc[maxm]={0},rc[maxm]={0},vis[maxm]={0},root[maxn],cnt=0,tim;
 23 vector<int>G[maxn];
 24 int f[maxn][20],d[maxn],dfn[maxn],size[maxn],q[maxn];
 25 struct cmp{bool operator()(int x,int y)const{return dfn[x]<dfn[y];}};
 26 set<int,cmp>st[maxn];
 27 int T,n,m,lgn,a[maxn],x,s,t,k,ans;
 28 int main(){
 29     scanf("%d",&T);
 30     while(T--){
 31         scanf("%d%d",&n,&m);
 32         clear(n);
 33         for(int i=1;i<=n;i++)scanf("%d",&a[i]);
 34         for(int i=2;i<=n;i++){
 35             scanf("%d",&f[i][0]);
 36             G[f[i][0]].push_back(i);
 37         }
 38         bfs();
 39         for(int j=1;j<=lgn;j++)for(int i=1;i<=n;i++)f[i][j]=f[f[i][j-1]][j-1];
 40         for(int i=1;i<=n;i++){
 41             x=q[i];
 42             if(!root[d[x]])root[d[x]]=root[d[x]-1];
 43             tim=d[x];
 44             k=1;
 45             t=dfn[x];
 46             build(1,n,root[d[x]]);
 47             set<int,cmp>::iterator u=st[a[x]].lower_bound(x),v=st[a[x]].upper_bound(x);
 48             if(u==st[a[x]].begin())u=st[a[x]].end();
 49             else if(u!=st[a[x]].end())u--;
 50             else if(!st[a[x]].empty()&&dfn[*st[a[x]].rbegin()]<dfn[x])u=st[a[x]].find(*st[a[x]].rbegin());
 51             if(u!=st[a[x]].end()&&v!=st[a[x]].end()){
 52                 t=dfn[LCA(*u,*v)];
 53                 build(1,n,root[d[x]]);
 54             }
 55             k=-1;
 56             if(u!=st[a[x]].end()){
 57                 t=dfn[LCA(*u,x)];
 58                 build(1,n,root[d[x]]);
 59             }
 60             if(v!=st[a[x]].end()){
 61                 t=dfn[LCA(x,*v)];
 62                 build(1,n,root[d[x]]);
 63             }
 64             st[a[x]].insert(x);
 65         }
 66         for(int i=1;i<=n;i++)if(!root[i])root[i]=root[i-1];
 67         while(m--){
 68             scanf("%d%d",&x,&k);
 69             x^=ans;k^=ans;
 70             s=dfn[x];
 71             t=dfn[x]+size[x]-1;
 72             ans=0;
 73             query(1,n,root[min(d[x]+k,n)]);
 74             printf("%d\n",ans);
 75         }
 76     }
 77     return 0;
 78 }
 79 void clear(int n){
 80     fill(sm,sm+cnt+1,0);
 81     fill(lc,lc+cnt+1,0);
 82     fill(rc,rc+cnt+1,0);
 83     fill(vis,vis+cnt+1,0);
 84     cnt=tim=0;
 85     fill(root,root+n+1,0);
 86     for(int i=0;i<=n;i++){
 87         G[i].clear();
 88         memset(f[i],0,sizeof(f[i]));
 89         st[i].clear();
 90     }
 91     fill(d,d+n+1,0);
 92     fill(dfn,dfn+n+1,0);
 93     fill(size,size+n+1,0);
 94     lgn=ans=0;
 95 }
 96 void bfs(){
 97     int x,head=1,tail=1;
 98     q[tail++]=1;
 99     while(head!=tail){
100         x=q[head++];
101         dfn[x]=size[x]=1;
102         d[x]=d[f[x][0]]+1;
103         while((1<<lgn)<d[x])lgn++;
104         for(int i=0;i<(int)G[x].size();i++)q[tail++]=G[x][i];
105     }
106     for(int i=n;i>1;i--){
107         x=q[i];
108         dfn[x]+=size[f[x][0]];
109         size[f[x][0]]+=size[x];
110     }
111     for(int i=2;i<=n;i++)dfn[q[i]]+=dfn[f[q[i]][0]]-1;
112 }
113 int LCA(int x,int y){
114     if(d[x]!=d[y]){
115         if(d[x]<d[y])swap(x,y);
116         for(int i=lgn;i>=0;i--)if(d[f[x][i]]>=d[y])x=f[x][i];
117     }
118     if(x==y)return x;
119     for(int i=lgn;i>=0;i--)if(f[x][i]!=f[y][i]){
120         x=f[x][i];
121         y=f[y][i];
122     }
123     return f[x][0];
124 }
125 void build(int l,int r,int &rt){
126     if(vis[rt]<tim)rt=copy(rt);
127     sm[rt]+=k;
128     if(l==r)return;
129     int mid=(l+r)>>1;
130     if(t<=mid)build(l,mid,lc[rt]);
131     else build(mid+1,r,rc[rt]);
132 }
133 void query(int l,int r,int rt){
134     if(!rt)return;
135     if(s<=l&&t>=r){
136         ans+=sm[rt];
137         return;
138     }
139     int mid=(l+r)>>1;
140     if(s<=mid)query(l,mid,lc[rt]);
141     if(t>mid)query(mid+1,r,rc[rt]);
142 }
143 int copy(int rt){
144     int x=++cnt;
145     sm[x]=sm[rt];
146     lc[x]=lc[rt];
147     rc[x]=rc[rt];
148     vis[x]=tim;
149     return x;
150 }
View Code

 

posted @ 2017-03-23 17:26  AntiLeaf  阅读(157)  评论(0编辑  收藏  举报