RXD and dividing

来源:互联网 发布:python怎么多线程并发 编辑:程序博客网 时间:2024/06/15 06:40

题意:给出一棵有n个顶点的树,然后将2~n号顶点分成k块,求1号顶点到分成k块后各个顶点的最大权值和。

把1看成整棵树的根. 问题相当于把2\sim n2n每个点一个[1, k][1,k]的标号. 然后根据最小斯坦纳树的定义, (x, fa_x)(x,fax) 这条边的贡献是 x 子树内不同标号的个数目dif_idifi. 那么显然有dif_i\leq min(k, sz_i)difimin(k,szi)sz_iszi表示子树大小. 可以通过构造让所有dif_idifi都取到最大值. 所以答案就是\sum_{x = 2}^{n}{w[x][fa_x] * min(sz_x, k)}x=2nw[x][fax]min(szx,k)时间复杂度O(n)O(n).

他给的图已经是一个最小生成树,如果将某些子结点分成与父亲结点不同的块的话,那么到达这些子结点就需要重用到达父亲结点的边,也就是相应权值。

#include<bits/stdc++.h>using namespace std;const int N=1000005;int n,k;struct node{    int v,w;};vector<node> vec[1000005];node temp;int Size[N];int w[N];void dfs(int u,int pre){    Size[u]=1;    int len=vec[u].size();    for(int i=0;i<len;i++)    {        int v=vec[u][i].v;        if(v!=pre)        {            w[v]=vec[u][i].w;            dfs(v,u);            Size[u]+=  Size[v];        }    }}int main(){    #ifndef ONLEINE_JUDGE    //freopen("in.txt","r",stdin);    #endif // ONLEINE_JUDGE    std::ios::sync_with_stdio(false);    int a,b,c;    while(cin>>n>>k)    {        for(int i=1;i<=n;i++)        {            w[i]=0;            Size[i]=0;            vec[i].clear();        }        for(int i=1;i<n;i++)        {            cin>>a>>b>>c;            temp.v=a;            temp.w=c;            vec[b].push_back(temp);            temp.v=b;            vec[a].push_back(temp);        }        dfs(1,-1);        long long sum=0;        for(int i=2;i<=n;i++)        {            sum+= (long long )w[i] * min(k,Size[i]);        }        cout<<sum<<endl;    }}


原创粉丝点击