题目描述 Description
在幻想乡,藤原妹红是拥有不老不死能力的人类。虽然不喜欢与人们交流,妹红仍然保护着误入迷途竹林村民。由于算得上是幻想乡最强的人类,对于她而言,迷途竹林的单向道路亦可以逆行。在妹红眼中,迷途竹林可以视为一个由N个路口(编号1..N),M条不同长度双向路连接的区域。妹红所在的红之自警队为了方便在迷途竹林中行动,绘制了一张特殊的迷途竹林地图,这张地图上只保留了N-1条道路,这些道路保证了任意两个路口间有且仅有一条路径,并且满足所有保留的道路长度之和最小,我们称这些道路为『自警队道路』。现在妹红打算在其中一个连接有多条『自警队道路』的路口设立根据地,当去掉根据地这个根据地所在路口后,就会出现某些路口间无法通过『自警队道路』相互连通的情况,我们认为这时仍然能够通过『自警队道路』连通的路口属于同一个『区域』。妹红希望最后每个『区域』的『自警队道路』总长尽可能平均,请计算出她应该选择哪一个路口作为根据地。
下例中红色的路口为妹红选择的根据地,实线边表示『自警队道路』,绿色虚线边表示非『自警队道路』,数字表示边权,『自警队道路』中相同颜色的实线边代表属于同一个『区域』:
(尽可能平均即权重最小,设每一块『区域』的路线总长为Length[i],平均路线长度为Avg=SUM{Length[i]}/区域数,权重d=∑( (Length[i]-Avg)^2 ) )
输入描述 Input Description
第1行:2个正整数N,M
第2..M+1行:每行2个整数u,v和1个实数len,表示u,v之间存在长度为len的边
输出描述 Output Description
第1行:1个整数,最后选择的路口编号,存在多个可选路口时选择编号小的
样例输入 Sample Input
3 3
3 1 5
3 2 4
1 2 3
样例输出 Sample Output
2
数据范围及提示 Data Size & Hint
对于60%的数据:3 ≤ N ≤ 2,000,N-1 ≤ M ≤ 50,000
对于100%的数据:3 ≤ N ≤ 40,000,N-1 ≤ M ≤ 200,000
对于100%的数据:0 < len ≤ 100,000,000
提示
样例解释:
妹红的『自警队道路』为(1,2)和(2,3)。
只能选择2作为根据地,产生的两个区域Length[i]分别为3和4。
所以方差为:(4-3.5)^2 + (3-3.5)^2 = 0.5
注意:
保证不存在相同距离的线路,两个路口间可能出现多条路径,且任意点对间至少存在一条路径。
本来想是树上最长链的中点,即树的中心…但其实并不是这样,因为要求方差最小,而断开某个点所分成的份数是不一样的,并且树的中心也不一定只有一个,所以就可以排除。
这样就可以树形DP了,思想很简单,按公式来就好。
务必注意是double类型!!!
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int SZ = 3000010;
const double INF = 1e30;
int n,m;
int head[SZ],nxt[SZ],tot = 0,ans,num[SZ];
struct edge{
int t;
double d;
}l[SZ];
void build(int f,int t,double d)
{
l[++ tot].t = t;
l[tot].d = d;
nxt[tot] = head[f];
head[f] = tot;
}
double dist[SZ],sum = 0;
double maxd = INF;
double dfs(int u,int fa)
{
double avg = sum/(double)num[u];
double d = 0,son = 0;
for(int i = head[u];i;i = nxt[i])
{
int v = l[i].t;
if(v == fa) continue;
dist[v] = l[i].d + dfs(v,u);
d += (dist[v] - avg) * (dist[v] - avg);
son += dist[v];
}
d += (sum - son - avg) * (sum - son - avg);
// cout<<u<<" "<<avg<<" "<<d<<" "<<son<<endl;
if(num[u] != 1)
if(d < maxd || (d == maxd && ans > u)) ans = u,maxd = d;
return son;
}
struct haha{
int f,t;
double d;
}e[SZ];
int fa[SZ];
int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
bool cmp(haha a,haha b) { return a.d < b.d; }
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i ++) fa[i] = i;
for(int i = 1;i <= m;i ++)
{
scanf("%d%d%lf",&e[i].f,&e[i].t,&e[i].d);
}
sort(e + 1,e + 1 + m,cmp);
for(int i = 1;i <= m;i ++)
{
int x = find(e[i].f);
int y = find(e[i].t);
if(x != y)
{
fa[x] = y;
build(e[i].f,e[i].t,e[i].d); build(e[i].t,e[i].f,e[i].d);
num[e[i].f] ++; num[e[i].t] ++;
sum += e[i].d;
}
}
dfs(1,0);
printf("%d",ans);
return 0;
}