题目背景
十个地方十人十色
全部都是猥琐大叔
这里也是那里也是
行踪可疑
现如今hentai横行,警察叔叔们不得不采取特♂殊手段惩戒这些家伙
题目描述
魅力之都是一个有N个路口,M条双向道路连接的城市。警察叔叔绘制了一张特殊的地图,在地图上只保留了N-1条道路,我们称这些道路为【特殊道路】,要保证任意两个路口间有且仅有一条路径,且满足所有保留的道路长度之和最小。
现在要在其中一个连接有多条【特殊道路】的路口设立【根据地】,去掉【根据地】所在路口后,就会出现某些路口间无法通过【特殊道路】相互连通的情况,我们认为这时仍然能够通过【特殊道路】连通的路口属于同一个【区域】。警察叔叔希望最后每个【区域】的【特殊道路】总长尽可能平均。警察叔叔找到了hzwer,但是hzwer是个无向图和有向图都无法区分的蒟蒻,请你帮他计算出应该选择哪一个路口作为【根据地】。
(尽可能平均即权值最小,设每一块【区域】的路线总长为Length[i](包括连接【根据地】与该【区域】的边),平均路线长度为Avg=SUM{Length[i]}/区域数,权值d=∑ (Length[i]-Avg)^2
输入格式
第1行:2个正整数N,M
第2..M+1行:每行2个整数u,v和1个实数len,表示u,v之间存在长度为len的边
输出格式
第1行:1个整数,最后选择的路口编号(存在多个可选路口时选择编号小的)
样例数据 1
样例数据 2
备注
对于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
保证不存在相同距离的线路,两个路口间可能出现多条路径,且任意点对间至少存在一条路径
首先最小生成树搞出来
然后dfs随便搞成一棵树
枚举每一个点,和它连通的部分就是它的每一个子树和整棵树除了它所在的子树以外的各个部分
它是长这样子的
在dfs的时候维护节点的子树个数和子树中的边权和
然后就可做了。注意权值相同取最小,所以要倒for
其实是水题……但是比赛时保存最小值的才开100e就30分……不能忍啊……比赛完开到5000ee就A了
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> #include<queue> #include<deque> #include<set> #include<map> #include<ctime> #define LL long long #define inf 0x7ffffff #define pa pair<int,int> #define pi 3.1415926535897932384626433832795028841971 #define N 100010 #define M 300010 using namespace std; struct MST{int l,r;double x;}bian[M]; struct edge{int to,next;double v;}e[2*M]; int n,m,cnt,ans,dsu[N]; int head[N]; int fa[N]; int sontype[N]; double tot,sumv[N]; bool mrk[N]; bool operator < (const MST &a,const MST &b){return a.x<b.x;} inline int getfa(int x){return dsu[x]==x?x:dsu[x]=getfa(dsu[x]);} inline void ins(int u,int v,double w) { e[++cnt].to=v; e[cnt].v=w; e[cnt].next=head[u]; head[u]=cnt; } inline void insert(int u,int v,double w) { ins(u,v,w); ins(v,u,w); } inline void dfs(int now) { if (mrk[now])return; mrk[now]=1; for (int i=head[now];i;i=e[i].next) if(!mrk[e[i].to]) { sontype[now]++; dfs(e[i].to); fa[e[i].to]=now; sumv[now]+=e[i].v+sumv[e[i].to]; } } inline LL read() { LL x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int main() { n=read();m=read(); for (int i=1;i<=m;i++) { bian[i].l=read(); bian[i].r=read(); scanf("%lf",&bian[i].x); } sort(bian+1,bian+m+1); tot=50000000000000000000.0; for (int i=1;i<=n;i++)dsu[i]=i; for (int i=1;i<=m;i++) { int x=getfa(bian[i].l); int y=getfa(bian[i].r); if (x==y)continue; insert(bian[i].l,bian[i].r,bian[i].x); dsu[x]=y; } dfs(1); for (int i=n;i>=1;i--) { int son=sontype[i]+(fa[i]!=0); if (son<2)continue; double sum=0,avg=sumv[1]/son,res=sumv[1]-sumv[i]; for (int j=head[i];j;j=e[j].next) if (e[j].to!=fa[i]) { sum+=(double)(e[j].v+sumv[e[j].to]-avg)*(e[j].v+sumv[e[j].to]-avg); } if (i!=1)sum+=(res-avg)*(res-avg); if(sum<=tot) { tot=sum; ans=i; } } printf("%d\n",ans); }