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;
}
感谢队友阿忠哥