BZOJ 4771 七彩树

来源:互联网 发布:澳洲女留学生 知乎 编辑:程序博客网 时间:2024/05/16 23:49

Description

给定一棵n个点的有根树,编号依次为1到n,其中1号点是根节点。每个节点都被染上了某一种颜色,其中第i个节
点的颜色为c[i]。如果c[i]=c[j],那么我们认为点i和点j拥有相同的颜色。定义depth[i]为i节点与根节点的距离
,为了方便起见,你可以认为树上相邻的两个点之间的距离为1。站在这棵色彩斑斓的树前面,你将面临m个问题。
每个问题包含两个整数x和d,表示询问x子树里且depth不超过depth[x]+d的所有点中出现了多少种本质不同的颜色
。请写一个程序,快速回答这些询问。

Input

第一行包含一个正整数T(1<=T<=500),表示测试数据的组数。
每组数据中,第一行包含两个正整数n(1<=n<=100000)和m(1<=m<=100000),表示节点数和询问数。
第二行包含n个正整数,其中第i个数为c[i](1<=c[i]<=n),分别表示每个节点的颜色。
第三行包含n-1个正整数,其中第i个数为f[i+1](1<=f[i]<i),表示节点i+1的父亲节点的编号。
接下来m行,每行两个整数x(1<=x<=n)和d(0<=d<n),依次表示每个询问。
输入数据经过了加密,对于每个询问,如果你读入了x和d,那么真实的x和d分别是x xor last和d xor last,
其中last表示这组数据中上一次询问的答案,如果这是当前数据的第一组询问,那么last=0。
输入数据保证n和m的总和不超过500000。

Output

对于每个询问输出一行一个整数,即答案。

Sample Input

1
5 8
1 3 3 2 2
1 1 3 3
1 0
0 0
3 0
1 3
2 1
2 0
6 2
4 1

Sample Output

1
2
3
1
1
2
1
1

HINT

Source

By Claris

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

dfs序+主席树+set+思路~

我们首先假设每个点的贡献是1,那么同色两点对于其lca的贡献就要-1,所以我们记录将同一个深度的点按照dfs序排序并记录在set中,那么dfs序中相邻两点就是应该减去的贡献。注意如果两边的点与中间点的贡献值都减去了,那么一定还要加上两边点的贡献值,这里用到了容斥原理。

这些贡献值的信息储存在主席树中。


#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<set>using namespace std;int t,n,m,x,y,a[100001],id[100001],fi[100001],ne[200001],w[200001],cnt,dep[100001];int fa[100001][18],siz[100001],dfn[100001],rt[100001],v[10000001],c[10000001][2],ans;struct node{int id,x;};set<node> se[100001];int read(){int x=0,f=1;char ch=getchar();while(ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}while(ch>='0' && ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}bool operator < (node u,node v){return u.id<v.id;}bool cmp(int u,int v){return dep[u]<dep[v];}void add(int u,int v){w[++cnt]=v;ne[cnt]=fi[u];fi[u]=cnt;}void dfs(int u){siz[u]=1;dfn[u]=++cnt;for(int i=1;i<=17;i++) fa[u][i]=fa[fa[u][i-1]][i-1];for(int i=fi[u];i;i=ne[i]) dep[w[i]]=dep[u]+1,fa[w[i]][0]=u,dfs(w[i]),siz[u]+=siz[w[i]];}int lca(int u,int v){if(dep[u]<dep[v]) swap(u,v);for(int i=17;~i;i--) if(dep[fa[u][i]]>=dep[v]) u=fa[u][i];if(u==v) return u;for(int i=17;~i;i--) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];return fa[u][0];}void add(int &now,int las,int l,int r,int u,int vv){now=++cnt;memcpy(c[now],c[las],sizeof(c[las]));v[now]=v[las]+vv;if(l==r) return;int mid=l+r>>1;if(mid>=u) add(c[now][0],c[las][0],l,mid,u,vv);else add(c[now][1],c[las][1],mid+1,r,u,vv);}int cal(int now,int l,int r,int u,int vv){if(!now) return 0;if(l>=u && r<=vv) return v[now];int mid=l+r>>1,no=0;if(u<=mid) no+=cal(c[now][0],l,mid,u,vv);if(vv>mid) no+=cal(c[now][1],mid+1,r,u,vv);return no;}int main(){t=read();while(t--){n=read();m=read();dep[1]=1;cnt=0;ans=0;memset(fi,0,sizeof(fi));memset(fa,0,sizeof(fa));for(int i=1;i<=n;i++) a[i]=read(),id[i]=i;for(int i=2;i<=n;i++) x=read(),add(x,i);cnt=0;dfs(1);sort(id+1,id+n+1,cmp);cnt=0;for(int i=1,now=1;i<=n;i++){rt[i]=rt[i-1];for(;now<=n && dep[id[now]]==i;now++){x=id[now];add(rt[i],rt[i],1,n,dfn[x],1);set<node> :: iterator k=se[a[x]].insert((node){dfn[x],x}).first,k1=k,k2=k;k1--;k2++;if(k!=se[a[x]].begin() && k2!=se[a[x]].end()) add(rt[i],rt[i],1,n,dfn[lca((*k1).x,(*k2).x)],1);if(k!=se[a[x]].begin()) add(rt[i],rt[i],1,n,dfn[lca((*k1).x,x)],-1);if(k2!=se[a[x]].end()) add(rt[i],rt[i],1,n,dfn[lca(x,(*k2).x)],-1);}}while(m--){x=read()^ans;y=read()^ans;printf("%d\n",ans=cal(rt[min(dep[x]+y,n)],1,n,dfn[x],dfn[x]+siz[x]-1));}for(int i=1;i<=n;i++) se[i].clear();}return 0;}



原创粉丝点击