NEUQOJ 2014 Defending Plan Support

NEUQOJ 2014 Defending Plan Support

题意

给一棵树,有边权和点权,要求一个结点,使得该点到各个结点的距离乘以各个点的点权之和最小。
省赛的时候我们队谁都不会写,没写过这种题,赛后也只有阿忠哥补了,很惭愧。

思路

其实这题和边权没多大关系,因为不管怎么样,重心离重的子树越近越好,不用管有多近,影响的只是答案而已,不影响策略。所以基本就是个裸的树重心了。

代码

#include <iostream>
#include <vector>
#include <queue>
#include <cstring>

using namespace std;
struct edge
{
    long long to;
    long long weight;
    long long nxt;
    edge(long long t,long long w,long long n):to(t),weight(w),nxt(n){
    }
};
vector<edge> edges;
int egs[500005];
void addedge(long long f,long long t,long long w)
{
    edges.emplace_back(t,w,egs[f]);
    egs[f]=edges.size()-1;
}

long long nn;
long long sizer[500005];
long long sumer;
long long weighter[500005];
long long center;
long long centerv;
void dfs(long long now,long long fa)
{
    sizer[now]=0;
    long long maxson=0;
    for(long long i=egs[now];i!=-1;i=edges[i].nxt) {
        long long nxter = edges[i].to;
        if (nxter != fa){
            dfs(nxter,now);
            sizer[now]+=sizer[nxter];
            maxson=max(sizer[nxter],maxson);
        }
    }
    sizer[now]+=weighter[now];
    maxson=max(maxson,sumer-sizer[now]);
    if(maxson<centerv){
        center=now;
        centerv=maxson;
    }
}
bool vis[500005];
long long leveler[500005];
long long bfs(long long s)
{
    memset(vis,0,(sizeof vis[0])*nn+5);
    memset(leveler,0,(sizeof leveler[0])*nn+5);
    queue<long long> qq;
    long long ans=0;
    qq.push(s);
    while(!qq.empty())
    {
        long long now=qq.front();
        qq.pop();
        vis[now]=true;
        for(long long i=egs[now];i!=-1;i=edges[i].nxt){
            long long nxter=edges[i].to;
            if(!vis[nxter]){
                leveler[nxter]=leveler[now]+edges[i].weight;
                ans+=leveler[nxter]*weighter[nxter];
                qq.push(nxter);
            }
        }
    }
    return ans;
}
int main() {
    while(cin>>nn) {
        edges.clear();
        sumer=0;
        memset(egs,-1,(sizeof egs[0])*nn+5);
        centerv=0x3f3f3f3f;
        for (long long i = 0; i < nn - 1; i++) {
            long long a, b, c;
            cin >> a >> b >> c;
            addedge(a,b,c);
            addedge(b,a,c);
        }
        for(long long i=1;i<=nn;i++)
        {
            cin>>weighter[i];
            sumer+=weighter[i];
        }
        dfs(1,0);
        cout<<bfs(center)<<endl;
    }
    return 0;
}

感谢队友阿忠哥

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值