[BZOJ]2017省队十连测推广赛1 T2.七彩树
题目大意:给你一棵n个点的树,每个点有颜色,m次询问,每次询问一个点x的子树内深度不超过depth[x]+d的节点的颜色数量,强制在线。(n,m<=100000,多组数据,保证n,m总和不超过500000)
思路:若不考虑深度限制,我们可以先给每个点赋点权1,再把每种颜色的节点按dfs序排序后相邻的节点的LCA的点权减1,每次求子树和即可回答询问,若有限制深度,我们可以按深度顺序把点一个个加入树中,每种颜色用个set维护,强制在线只要把求子树和的线段树可持久化就可以了,总复杂度O(nlogn)。
#include<cstdio> #include<cstring> #include<algorithm> #include<set> using namespace std; inline int read() { int x;char c; while((c=getchar())<'0'||c>'9'); for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0'; return x; } #define MN 100000 #define K 17 #define ND 8000000 struct edge{int nx,t;}e[MN+5]; int h[MN+5],en,c[MN+5],d[MN+5],l[MN+5],r[MN+5],cnt,fa[K][MN+5],p[MN+5],rt[MN+5],tn; class stcmp{public:inline bool operator()(int a,int b){return l[a]<l[b];}}; set<int,stcmp> st[MN+5]; set<int,stcmp>::iterator x,y,z; struct node{int l,r,s;}t[ND+5]; int renew(int x,int l,int r,int k,int z) { int p=++tn,mid=l+r>>1; if(l==r)return t[p]=(node){0,0,t[x].s+z},p; if(k<=mid)return t[p]=(node){renew(t[x].l,l,mid,k,z),t[x].r,t[x].s+z},p; return t[p]=(node){t[x].l,renew(t[x].r,mid+1,r,k,z),t[x].s+z},p; } int query(int x,int l,int r,int L,int R) { if(l==L&&r==R)return t[x].s; int mid=l+r>>1; if(R<=mid)return query(t[x].l,l,mid,L,R); if(L>mid)return query(t[x].r,mid+1,r,L,R); return query(t[x].l,l,mid,L,mid)+query(t[x].r,mid+1,r,mid+1,R); } inline void ins(int x,int y){e[++en]=(edge){h[x],y};h[x]=en;} void dfs(int x) { l[x]=++cnt; for(int i=h[x];i;i=e[i].nx)d[e[i].t]=d[x]+1,dfs(e[i].t); r[x]=cnt; } bool cmp(int a,int b){return d[a]<d[b];} int lca(int x,int y) { int dx=d[x]-d[y],i; if(dx<0)dx=-dx,swap(x,y); for(i=0;dx;dx>>=1,++i)if(dx&1)x=fa[i][x]; if(x==y)return x; for(i=K;i--;)if(fa[i][x]!=fa[i][y])x=fa[i][x],y=fa[i][y]; return fa[0][x]; } int main() { int T,n,m,i,j,t; for(T=read();T--;) { n=read();m=read(); for(i=1;i<=n;++i)c[i]=read(),p[i]=i,st[i].clear(); memset(h,t=tn=en=cnt=0,sizeof(int)*(n+1)); for(i=2;i<=n;++i)ins(fa[0][i]=read(),i); for(i=1;i<K;++i)for(j=1;j<=n;++j)fa[i][j]=fa[i-1][fa[i-1][j]]; dfs(1);sort(p+1,p+n+1,cmp); for(i=1;i<=n;++i) { t=renew(t,1,n,l[p[i]],1); st[c[p[i]]].insert(p[i]); x=y=z=st[c[p[i]]].find(p[i]);--x;++z; if(y!=st[c[p[i]]].begin()&&z!=st[c[p[i]]].end())t=renew(t,1,n,l[lca(*x,*z)],1); if(y!=st[c[p[i]]].begin())t=renew(t,1,n,l[lca(*x,*y)],-1); if(z!=st[c[p[i]]].end())t=renew(t,1,n,l[lca(*y,*z)],-1); rt[d[p[i]]]=t; } for(t=0;m--;) { i=read()^t;j=read()^t; printf("%d\n",t=query(rt[d[i]+j>d[p[n]]?d[p[n]]:d[i]+j],1,n,l[i],r[i])); } } }