• 2020ccpc威海 Rencontre


    太可惜了,难过

    真的难受啊

    对于树上三个点a,b,c 汇于一个点的最短路和 ans,有dis(a,b) + dis(b,c) + dis(c,a) = ans * 2

    知道这个以后就可以用换根dp解决了,假设dp[x][i]表示所有i颜色的节点到x的距离和

    具体可以看代码,

    注意答案会爆long long 

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<cstdio>
    #include<vector>
    using namespace std;
    typedef long long ll;
    const int maxn = 2e5+11;
    ll gcd(ll a,ll b){
        return b == 0 ? a:gcd(b,a%b);
    }
    
    
    struct Node{
        int p;
        ll len;
        Node(int a,ll ln):p(a),len(ln){}
    };
    vector<Node>G[maxn];
    void add(int x,int y,ll len){
        G[x].push_back(Node(y,len));
    }
    ll dp[maxn][5];//i号点到x 的距离和
     
    ll cnt[maxn][5];
    
    int dfs(int x,int fa){
        dp[x][1] = dp[x][2] = dp[x][3] = 0;
        int l = G[x].size();
        for(int i=0;i<l;i++){
            int p = G[x][i].p;
            ll len = G[x][i].len;
            if(p == fa) continue;
            dfs(p,x);
            for(int j=1;j<=3;j++){
                cnt[x][j] += cnt[p][j];
                dp[x][j] += dp[p][j] + len * cnt[p][j];
            }
        }
        return 0;
    }
    int dfs2(int x,int fa){
        int l = G[x].size();
        for(int i=0;i<l;i++){
            int p = G[x][i].p;
            ll len = G[x][i].len;
            if(p == fa) continue;
            for(int j=1;j<=3;j++){
                dp[p][j] += dp[x][j] - dp[p][j] - cnt[p][j]*len + (cnt[x][j] - cnt[p][j])*len;
                cnt[p][j] = cnt[x][j];
            }
            dfs2(p,x);
        }
        return 0;
    }
     
    double a[4];
    int list[maxn][5];
    int main(){
        int n;
        scanf("%d",&n);
        for(int i=1;i<n;i++){
            int x,y;
            ll len;
            scanf("%d %d %lld",&x,&y,&len);
            add(x,y,len);
            add(y,x,len);
        }
        ll c = 1;
        for(int i=1;i<=3;i++){
            int k;
            scanf("%d",&k);
            c *= k;
            a[i] = k;
            
            while(k--){
                int x;
                scanf("%d",&x);
                cnt[x][i] = 1;
                list[x][i] = 1;
            }
        }
        
        dfs(1,-1);
        dfs2(1,-1);
        c *= 2;
        
        double ans = 0;
        double aa = 0;
        double bb = 0;
        double cc = 0;
        
        
        for(int i=1;i<=n;i++){
            if(list[i][1]){
                aa += dp[i][2];
            }
            if(list[i][2]){
                bb += dp[i][3];
            }
            if(list[i][3]){
                cc += dp[i][1];
            }
        } 
        
        double cns = aa * a[3] + bb*a[1] + cc * a[2];
        
        printf("%lf
    ",cns/c);
    
        return 0;
    }
    
    /*
    5
    1 2 3
    1 3 5
    2 4 7
    2 5 11
    2 2 4
    2 1 2
    2 1 5
    
    */
    

      

    寻找真正的热爱
  • 相关阅读:
    zabbix邮件报警
    简单的带权随机算法
    一、向量
    C#遍历DataSet
    旅游(二)——广州
    旅游(一)——潮州
    LoRa术语
    Linux基础(一)
    Git(二)_基本命令
    Git使用(一)——Cygwin
  • 原文地址:https://www.cnblogs.com/lesning/p/13881005.html
Copyright © 2020-2023  润新知