• 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
    ",ans);
        return 0;
    }
    

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

  • 相关阅读:
    css基础教程
    网页加载-上下幕布分开
    Vue-Aixos
    webpack学习
    Vue、Element 路由跳转,左侧菜单高亮显示,页面刷新不会改变当前高亮菜单
    Vue知识概括
    JSON.parse() 与 JSON.stringify()
    Bootstrap4 样式笔记
    ES6基础语法
    V-model 双向绑定的原理是什么?
  • 原文地址:https://www.cnblogs.com/luoyugongxi/p/13887399.html
Copyright © 2020-2023  润新知