zoukankan      html  css  js  c++  java
  • 题解-CF101D Castle

    题面

    CF101D Castle

    给一棵 (n) 个节点的带权树,求一种遍历方案,从 (1) 出发,每条边走两次,走过所有点,第一次经过每个节点的平均时间最小。输出这个平均时间。

    数据范围:(2le nle 10^5)


    题解

    可以对于每棵子树单独计算。

    虽然子树内走的顺序是不固定的,但是要消耗的总时间是固定的。

    (f_u) 表示 (u) 这棵子树内的第一次经过每个节点的 时间和(w_{u,v})(u,v) 两点间的边权,(sz_u)(u) 的子树大小,(szt_u) 是走遍 (u) 这棵子树的所需时间。

    由于每棵子树遍历一次而且有顺序,记 (v_i)(u)(i) 个遍历的子树。

    [f_u=sum_{i} [f_{v_i}+sz_{v_i}w_{u,v_i}+(szt_{v_i}+2w_{u,v})sum_{j>i} sz_{v_j}] ]

    (sum_{i} (f_{v_i}+sz_{v_i}w_{u,v_i})) 是顺序不同时固定的,(sum_{i} (szt_{v_i}+2w_{u,v})sum_{j>i} sz_{v_j}) 是会变的,所以这题的难点在于找到它的最小值。

    蒟蒻想了好久,这个式子很眼熟,但是怎么化都貌似不能贪心,于是请教了旁边的保队长。

    很明显,如果对于 (ige 3)(v_i) 都已经确定,那么 (p)(q) 分别作为 (v_1,v_2) 的贡献是

    [v_1=p,v_2=q:(szt_p+2w_{u,p})(sz_{q}+sum_{jge 3} sz_{v_j})+(szt_p+2w_{u,p})sum_{jge 3}sz_{v_j}+cdots ]

    [v_1=q,v_2=p:(szt_q+2w_{u,q})(sz_{p}+sum_{jge 3} sz_{v_j})+(szt_q+2w_{u,q})sum_{jge 3}sz_{v_j}+cdots ]

    其实差别就在于 ((szt_p+2w_{u,p})sz_{q})((szt_q+2w_{u,q})sz_{p}),而且手玩一下可以发现,对于任意两个 (v) 顺序都是类似的。

    所以把所有 (vin son_u) 丢进一个 vector,然后对于 (p)(q),按上面的差别排序即可。


    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    //Start
    typedef long long ll;
    typedef double db;
    #define mp(a,b) make_pair((a),(b))
    #define x first
    #define y second
    #define bg begin()
    #define ed end()
    #define sz(a) int((a).size())
    #define pb(a) push_back(a)
    #define R(i,a,b) for(int i=(a),i##E=(b);i<i##E;i++)
    #define L(i,a,b) for(int i=(b)-1,i##E=(a)-1;i>i##E;i--)
    const int iinf=0x3f3f3f3f;
    const ll linf=0x3f3f3f3f3f3f3f3f;
    
    //Data
    const int N=1e5;
    int n;
    
    //Tree
    vector<int> e[N],to,we;
    void adde(int u,int v,int w){
        e[u].pb(sz(to)),to.pb(v),we.pb(w);
        e[v].pb(sz(to)),to.pb(u),we.pb(w);
    }
    int sz[N],szt[N];
    ll dfs(int u,int fa){
        ll res=0; sz[u]=1,szt[u]=0;
        vector<int> cho;
        for(int v:e[u])if(to[v]^fa){
            res+=dfs(to[v],u);
            res+=1ll*we[v]*sz[to[v]];
            szt[to[v]]+=we[v]*2;
            sz[u]+=sz[to[v]],szt[u]+=szt[to[v]];
            cho.pb(to[v]);
        }
        sort(cho.bg,cho.ed,[&](int p,int q){
            return 1ll*szt[p]*sz[q]<1ll*szt[q]*sz[p];
        });
        int tot=sz[u]-1;
        for(int v:cho) tot-=sz[v],res+=1ll*szt[v]*tot;
        return res;
    }
    
    //Main
    int main(){
        ios::sync_with_stdio(0);
        cin.tie(0),cout.tie(0);
        cout.precision(12);
        cin>>n;
        R(i,1,n){int u,v,w; cin>>u>>v>>w,--u,--v,adde(u,v,w);}
        // cout<<dfs(0,-1)<<'
    ';
        cout<<fixed<<1.*dfs(0,-1)/(n-1)<<'
    ';
        return 0;
    }
    

    祝大家学习愉快!

  • 相关阅读:
    MySQL:Mysql字符串截取函数SUBSTRING的用法说明
    windows2003+iis6.0+php(fastcgi)5.3+wincache+memcached
    apache 80端口未被占用,启动不了的问题
    服务器端口大全
    UCenter 表结构
    “来自客户端名 a 的远程会话超出了所允许的失败登录最大次数。强行终止了会话。”原因及解决方法
    开发云应用从何入手?
    Building Nutch: Open Source Search
    Nutch0.9加入ICTCLAS 支持中文分词等(转)
    OWL解惑 :AllValuesFrom与Range的区别 关于Domain和Range
  • 原文地址:https://www.cnblogs.com/George1123/p/13851802.html
Copyright © 2011-2022 走看看