2020威海ccpc C Rencontre 树上dp染色问题

题面

这题面太毒瘤了

给n个点,n-1条边,组成一个树,三个人选其中的m1个点,m2个点,m3个点。然后三个人随便选一个地方住下,然后第二天到某一个点集合,是最小路径,求期望路径是多少

第二个样例

5
1 2 3
1 3 5
2 4 7
2 5 11
3 2 4 5
4 1 2 3 5
2 1 3

第二个人和第三个人重复了1,然后模拟比赛的时候翻译说不能同一家,然后样例一直输不对。。。赛后看题解,直接除以(m1 * m2 * m3)即可,不需要找重复……

就这句话直接把我们的翻译看懵了,然后手算样例算不对,笑死。

They decide to stay in separate hotels at night and meet in one hotel the next day. 

思路

其实是一道很经典的树上求贡献染色图(?)如果不知道这个可以看一下这篇博客

然后我的思路就是跑一边,然后求每个边做的贡献,把第1,2,3人当作红黄蓝染色

贡献就是:
(红左个数 * 黄右个数 * 蓝右个数 +

黄左个数 * 红右 个数* 蓝右个数 +

蓝左个数 * 黄右个数 * 红右个数 +

红左个数 * 黄左个数 * 蓝右个数 +

黄左个数 * 红右个数 * 蓝左个数 +

蓝左个数 * 黄右个数 * 红左个数)/m1/m2/m3 * 边长

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+9;
int n;
int ne[N<<1],to[N<<1],head[N],dis[N<<1],tot,yans[N][3];
ll sz[N][3];
int k[3];
double ans;
void inint(){
    tot=0;memset(head,-1,sizeof(head));
}
void add(int u,int v,int w){
    ne[tot]=head[u];
    to[tot]=v;
    dis[tot]=w;
    head[u]=tot++;
}
void dfs(int u,int fa){
    for(int i=0;i<3;i++){
        sz[u][i]=(ll)yans[u][i];
    }
    for(int i=head[u];~i;i=ne[i]){
        int v=to[i];if(v==fa)continue;
        dfs(v,u);
        for(int i=0;i<3;i++){
            sz[u][i]+=sz[v][i];
        }
    }
    for(int i=head[u];~i;i=ne[i]){
        int v=to[i];if(v==fa)continue;
        ll sum=0;
        sum+=(sz[v][0]*(k[1]-sz[v][1])*(k[2]-sz[v][2]))+(sz[v][1]*(k[0]-sz[v][0])*(k[2]-sz[v][2]));
        sum+=(sz[v][2]*(k[1]-sz[v][1])*(k[0]-sz[v][0]))+(sz[v][2]*sz[v][0]*(k[1]-sz[v][1]));
        sum+=(sz[v][0]*sz[v][1]*(k[2]-sz[v][2]))+(sz[v][2]*sz[v][1]*(k[0]-sz[v][0]));
       // cout<<u<<v<<(sum*dis[i]/(double)k[0]/(double)k[1]/(double)k[2])<<endl;
        ans+=((sum*1.0/(double)k[0]/(double)k[1]/(double)k[2])*(double)dis[i]);
    }
}
int main(){
    inint();
    scanf("%d",&n);
    for(int i=1;i<n;i++){
        int u,v,w;scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);add(v,u,w);
    }
    ans=0.0;
    for(int i=0;i<3;i++){
        scanf("%d",&k[i]);
        for(int j=0;j<k[i];j++){
            int num;scanf("%d",&num);
            yans[num][i]=1;
        }
    }
    dfs(1,0);
    printf("%f\n",ans);
    return 0;
}

小声哔哔一句,威海这人均4题,太猛了吧。。。模拟赛的时候各种wa飞,磕磕碰碰的4题……C题题面和样例解释不了,G题线段树不会写,但赛后补了一下哈希线段树,tml

posted @ 2020-10-27 20:37  ouluy  阅读(205)  评论(0编辑  收藏  举报