以深度建立线段树,线段树父亲节点向儿子节点连边,然后用线段树合并可以得到任何一个点子树的线段树,只需向对应节点的线段树中的$O(log n)$个点连边即可。为了保证连边关系不发生混乱,线段树需要进行可持久化。
这样建图,点数和边数都是$O(nlog n)$级别的,再求出强连通分量,用排列组合求出答案即可。
#pragma comment(linker, "/STACK:102400000,102400000") #include<cstdio> #include<cstdlib> const int N=100010,M=4000000,E=6000000; int Case,n,i,x,y,f[M],d[N],root[N],fin[N],l[M],r[M],tot; int gt[N],nxtt[N],vt[N],edt; int ga[N],nxta[N],va[N],la[N],ra[N],eda; int g[2][M],v[2][E],nxt[2][E],ed; int q[M],t,vis[M],cnt[M]; long long ans; void add(int x,int y){ vt[++edt]=y; nxtt[edt]=gt[x]; gt[x]=edt; } void addask(int x,int y,int l,int r){ va[++eda]=y; la[eda]=l; ra[eda]=r<n?r:n; nxta[eda]=ga[x]; ga[x]=eda; } void addedge(int x,int y){ if(!y)return; v[0][++ed]=y;nxt[0][ed]=g[0][x];g[0][x]=ed; v[1][ed]=x;nxt[1][ed]=g[1][y];g[1][y]=ed; } int merge(int x,int y,int a,int b){ if(!x)return y; if(!y)return x; int z=++tot; if(a==b){ addedge(z,x); addedge(z,y); return z; } int mid=(a+b)>>1; addedge(z,l[z]=merge(l[x],l[y],a,mid)); addedge(z,r[z]=merge(r[x],r[y],mid+1,b)); return z; } int build(int a,int b,int c){ int x=++tot; if(a==b)return x; int mid=(a+b)>>1; if(c<=mid)addedge(x,l[x]=build(a,mid,c));else addedge(x,r[x]=build(mid+1,b,c)); return x; } void ask(int x,int a,int b,int c,int d,int p){ if(!x)return; if(c<=a&&b<=d){ addedge(p,x); return; } int mid=(a+b)>>1; if(c<=mid&&l[x])ask(l[x],a,mid,c,d,p); if(d>mid&&r[x])ask(r[x],mid+1,b,c,d,p); } void dfs(int x){ for(int i=gt[x];i;i=nxtt[i]){ dfs(vt[i]); root[x]=merge(root[x],root[vt[i]],1,n); } for(int i=ga[x];i;i=nxta[i])ask(root[x],1,n,la[i],ra[i],va[i]); } void dfs1(int x){ vis[x]=1; for(int i=g[0][x];i;i=nxt[0][i])if(!vis[v[0][i]])dfs1(v[0][i]); q[++t]=x; } void dfs2(int x,int y){ vis[x]=0,f[x]=y; for(int i=g[1][x];i;i=nxt[1][i])if(vis[v[1][i]])dfs2(v[1][i],y); } int main(){ scanf("%d",&Case); while(Case--){ scanf("%d",&n); for(i=2;i<=n;i++)scanf("%d",&f[i]),add(f[i],i); for(i=1;i<=n;i++){ d[i]=d[f[i]]+1; root[i]=build(1,n,d[i]); fin[i]=tot; } for(i=1;i<=n;i++)scanf("%d%d",&x,&y),addask(x,fin[i],d[x],d[x]+y); dfs(1); for(i=1;i<=tot;i++)if(!vis[i])dfs1(i); for(i=tot;i;i--)if(vis[q[i]])dfs2(q[i],q[i]); for(i=1;i<=n;i++)cnt[f[fin[i]]]++; for(i=1;i<=tot;i++)if(cnt[i])ans+=1LL*cnt[i]*(cnt[i]-1)/2; printf("%I64d ",ans); for(i=1;i<=n;i++)gt[i]=ga[i]=f[i]=0; for(i=1;i<=tot;i++){ l[i]=r[i]=vis[i]=cnt[i]=0; g[0][i]=g[1][i]=0; } ans=tot=edt=eda=ed=t=0; } return 0; }