[最小生成樹][並查集]JZOJ 2940 生成輸入數據
阿新 • • 發佈:2019-01-19
return fieldset sam one code 我們 scanf 忽略 event
分析
題目和題面無關系列
考場的時候不知道為什麽總覺得可以有奇怪的方法,打了一波計算用set維護然後20分WA
事實上只用模仿生成最小生成樹的過程即可
我們合並兩棵樹時,我們可以確定其中必定只有一條邊是最小生成樹內的,需要添加的邊數=兩棵樹大小的乘積-1,邊的權值為最小生成樹樹邊的權值+1
然後再加上原樹總值就算出來了
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int N=2e4+10; struct Edge { int u,v,w; }g[N]; int f[N],sz[N]; int T,n;View Codeint Get_F(int x) {return f[x]==x?x:f[x]=Get_F(f[x]);} bool CMP(Edge a,Edge b) { return a.w<b.w; } int main() { for (scanf("%d",&T);T;T--) { scanf("%d",&n); for (int i=1;i<n;i++) scanf("%d%d%d",&g[i].u,&g[i].v,&g[i].w),sz[i]=1,f[i]=i; f[n]=n;sz[n]=1;long long ans=0; sort(g+1,g+n,CMP); for (int i=1;i<n;i++) { int fu=Get_F(g[i].u),fv=Get_F(g[i].v); if (fu!=fv) { ans+=1ll*(sz[fu]*sz[fv]-1ll)*(g[i].w+1ll); sz[fu]+=sz[fv]; f[fv]=fu; ans+=g[i].w; } } printf("%lld\n",ans); } }
[最小生成樹][並查集]JZOJ 2940 生成輸入數據