[Beijing2010組隊]次小生成樹Tree
阿新 • • 發佈:2018-02-16
list div %d nod include opera ace radius ott
小C最近學了很多最小生成樹的算法,Prim算法、Kurskal算法、消圈算法等等。正當小C洋洋得意之時,小P又來潑小C冷水了。小P說,讓小C求出一個無向圖的次小生成樹,而且這個次小生成樹還得是嚴格次小的,也就是說:如果最小生成樹選擇的邊集是EM,嚴格次小生成樹選擇的邊集是ES,那麽需要滿足:(value(e)表示邊e的權值) \sum_{e \in E_M}value(e)<\sum_{e \in E_S}value(e)∑e∈EM??value(e)<∑e∈ES??value(e)
這下小 C 蒙了,他找到了你,希望你幫他解決這個問題。
輸入輸出格式
輸入格式:
第一行包含兩個整數N 和M,表示無向圖的點數與邊數。 接下來 M行,每行 3個數x y z 表示,點 x 和點y之間有一條邊,邊的權值為z。
輸出格式:
包含一行,僅一個數,表示嚴格次小生成樹的邊權和。(數據保證必定存在嚴格次小生成樹)
輸入輸出樣例
輸入樣例#1:5 6 1 2 1 1 3 2 2 4 3 3 5 4 3 4 3 4 5 6輸出樣例#1: 復制
11
說明
數據中無向圖無自環; 50% 的數據N≤2 000 M≤3 000; 80% 的數據N≤50 000 M≤100 000; 100% 的數據N≤100 000 M≤300 000 ,邊權值非負且不超過 10^9 。
跑個最小生成樹然後LCA維護路徑最大和次大(嚴格)邊即可,利用了最小生成樹的環性質。
(我就想請問出題人忘了給邊排序是怎麽能過樣例hhhh,mdzz查錯了一個點最後發現沒給邊排序)
code:
#include<bits/stdc++.h> #define ll long long #define maxn 100005 using namespace std; ll base=0; struct lines{ int u,v,w; bool operator <(const lines &U)const{ return w<U.w; } }l[maxn*3]; struct node{ int m,cm; node operator +(const node &u)const{ node r; r.m=max(m,u.m); r.cm=max(cm,u.cm); if(m<r.m) r.cm=max(r.cm,m); if(u.m<r.m) r.cm=max(r.cm,u.m); return r; } }; const int inf=1e9; bool choose[maxn*3]; int ci[30],ans=inf; int to[maxn*2],ne[maxn*2]; int val[maxn*2],cnt=0,n,m; int f[maxn][20]; node g[maxn][20]; int hd[maxn],p[maxn],dep[maxn]; int ff(int x){ return p[x]==x?x:(p[x]=ff(p[x])); } inline void add(lines e){ to[++cnt]=e.v,ne[cnt]=hd[e.u],val[cnt]=e.w,hd[e.u]=cnt; to[++cnt]=e.u,ne[cnt]=hd[e.v],val[cnt]=e.w,hd[e.v]=cnt; } inline void kruscal(){ for(int i=1;i<=n;i++) p[i]=i; int fa,fb,tot=0; sort(l+1,l+m+1); n--; for(int i=1;i<=m;i++){ fa=ff(l[i].u),fb=ff(l[i].v); if(fa!=fb){ tot++,choose[i]=1; base+=(ll)l[i].w; add(l[i]),p[fa]=fb; if(tot==n) break; } } n++; } void dfs(int x,int fa){ for(int i=1;ci[i]<=dep[x];i++){ g[x][i]=g[x][i-1]+g[f[x][i-1]][i-1]; f[x][i]=f[f[x][i-1]][i-1]; } for(int i=hd[x];i;i=ne[i]) if(to[i]!=fa){ dep[to[i]]=dep[x]+1; f[to[i]][0]=x; g[to[i]][0]=(node){val[i],0}; dfs(to[i],x); } } inline node LCAMAX(int x,int y){ if(dep[x]<dep[y]) swap(x,y); int dt=dep[x]-dep[y]; node an=(node){0,0}; for(int i=0;ci[i]<=dt;i++) if(ci[i]&dt){ an=an+g[x][i]; x=f[x][i]; } if(x==y) return an; int s=log(dep[x])/log(2)+1; for(;s>=0;s--){ if(ci[s]>dep[x]) continue; if(f[x][s]!=f[y][s]){ an=an+g[x][s]+g[y][s]; x=f[x][s],y=f[y][s]; } } return an+g[x][0]+g[y][0]; } inline void solve(){ dep[1]=0; dfs(1,0); node tmp; for(int i=1;i<=m;i++) if(!choose[i]){ tmp=LCAMAX(l[i].u,l[i].v); // printf("%d %d %d\n",i,tmp.m,tmp.cm); if(tmp.m<l[i].w) ans=min(ans,l[i].w-tmp.m); else ans=min(ans,l[i].w-tmp.cm); } } int main(){ ci[0]=1; for(int i=1;i<=20;i++) ci[i]=ci[i-1]<<1; scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) scanf("%d%d%d",&l[i].u,&l[i].v,&l[i].w); kruscal(); solve(); cout<<(ll)ans+base<<endl; return 0; }
[Beijing2010組隊]次小生成樹Tree