zoukankan      html  css  js  c++  java
  • HDU5420 : Victor and Proposition

    以深度建立线段树,线段树父亲节点向儿子节点连边,然后用线段树合并可以得到任何一个点子树的线段树,只需向对应节点的线段树中的$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;
    }
    

      

  • 相关阅读:
    Navsion二次开发_学习笔记
    《软件开发者路线图:从学徒到高手》笔记
    Concurrency并发性
    Excel VBA 函数
    在excel worksheet中添加button 和对Excel workbook做权限控制相关的新知识
    outline (group) 在Excel worksheet 中
    自主学习进度(软件工程)
    四则运算实现2(JAVA)
    简单四则运算实现(JAVA)
    数学建模(Lingo)(非线性整数规划)
  • 原文地址:https://www.cnblogs.com/clrs97/p/4752990.html
Copyright © 2011-2022 走看看