• HDU 6035 Colorful Tree (树形DP)


    【题目链接】 http://acm.hdu.edu.cn/showproblem.php?pid=6035

    【题目大意】

      给出一颗树,一条路径的价值为其上点权的种类数,求路径总价值

    【题解】

      我们计算单个颜色的贡献,那么就是经过该颜色至少一次的路径数量,
      我们统计的时候在每个点记录以其为开始的路径的答案和,
      统计的时候计算了点自身,同时有重复计算的部分,最后减去n除以2即可
      那么我们只要在每种颜色的虚树上统计即可。
      对于子树的贡献需要区间修改,我们在dfs序的差分数组上更改,最后求前缀和即可。  

    【代码】

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <vector>
    #include <list> 
    using namespace std;
    const int M=200010,N=(M<<1)+10;
    int n,x,y,pre[N],st[N],en[N],c[N];
    vector<int> u[N],v[N];
    long long ans[N]; 
    list<int> l[N];
    int dfn;
    void dfs(int x,int fx){
        int cx=c[x];
        if(l[cx].empty())u[M+cx].push_back(x);
        else u[l[cx].back()].push_back(x);
        pre[x]=fx;
        l[cx].push_back(x);
        st[x]=dfn++;
        for(int i=0;i<v[x].size();i++){
            int y=v[x][i];
            if(y==fx)continue;
            dfs(y,x);
        }l[cx].pop_back();
        en[x]=dfn;
    }
    bool isson(int x,int y){return st[y]<=st[x]&&st[x]<en[y];}
    void Dfs(int x,int d){
        int pos=0;
        if(x<=M){
            ans[st[x]]+=n-d;
            ans[st[x]+1]-=n-d;
        }
        for(int i=0;i<v[x].size();i++){
            int y=v[x][i];
            if(y==pre[x])continue;
            int p=pos,size=en[y]-st[y];
            while(p<u[x].size()&&isson(u[x][p],y)){
                size-=en[u[x][p]]-st[u[x][p]];
                p++;
            }ans[st[y]]+=n-size-d;
            ans[en[y]]-=n-size-d;
            for(int j=pos;j<p;j++)Dfs(u[x][j],n-size);
            pos=p;
        }
    }
    int Cas=1;
    int main(){
        while(~scanf("%d",&n)){
            for(int i=1;i<=n;i++)scanf("%d",&c[i]);
            memset(ans,0,sizeof(ans));
            for(int i=0;i<N;i++)v[i].clear(),u[i].clear(),l[i].clear();
            dfn=1;
            for(int i=1;i<n;i++){
                scanf("%d%d",&x,&y);
                v[x].push_back(y);
                v[y].push_back(x);
            }dfs(1,1);
            for(int i=1;i<=M;i++){v[i+M].push_back(1);Dfs(i+M,0);}
            for(int i=1;i<=n;i++)ans[i]+=ans[i-1];
            long long Ans=0;
            for(int i=1;i<=n;i++)Ans+=ans[st[i]];
            printf("Case #%d: %lld
    ",Cas++,(Ans-n)/2);
        }return 0;
    }
  • 相关阅读:
    Algs4-1.1.27二项分布
    Algs4-1.1.25数学归纳法证明欧几里得算法
    Algs4-1.1.26证明以下代码能够将a、b、c按照升序排列
    Algs4-1.1.24欧几里得算法求最大公约数
    Algs4-1.1.23区分在与不在白名单中的值
    Algs4-1.1.22以缩进方式打印递归参数
    微服务架构是什么?
    python 迭代器
    python 列表推导
    python 创建二维数组的方法
  • 原文地址:https://www.cnblogs.com/forever97/p/hdu6035.html
Copyright © 2020-2023  润新知