HDU5420 : Victor and Proposition

以深度建立线段树,线段树父亲节点向儿子节点连边,然后用线段树合并可以得到任何一个点子树的线段树,只需向对应节点的线段树中的$O(\log n)$个点连边即可。为了保证连边关系不发生混乱,线段树需要进行可持久化。

这样建图,点数和边数都是$O(n\log 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\n",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;
}

  

posted @ 2015-08-23 19:10  Claris  阅读(377)  评论(0编辑  收藏  举报