BZOJ 1977 次小生成樹 倍增LCA
阿新 • • 發佈:2019-01-08
題目大意:給定一個無向圖,求嚴格次小生成樹
這題糾結了我同學很久。。。首先如果是不嚴格的次小生成樹(權值可以等於最小生成樹),那麼我們就有一個很簡單明瞭的演算法:
首先求出最小生成樹 然後建立倍增LCA 列舉沒進入最小生成樹的邊 在邊的兩端點的路徑上尋找最大的邊權 用最小生成樹權值-最大邊權+新邊權去更新ans即可
但是這道題是嚴格次小生成樹 那麼也好辦 我們記錄一個次大邊權 如果列舉到的邊權和最大邊權相等 就用路徑上的次大邊權代替最大邊權去更新即可
於是我們只需要在倍增的時候記錄最大權值和次大權值即可 注意建立倍增LCA的時候次大值的討論 這裡容易出問題
假期被罰十道題第一道。。。苦逼的娃,同學們都刷了四道了0.0 10%達成
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 100100 using namespace std; typedef long long ll; struct edge{ int x,y,f; bool used; bool operator < (const edge &y) const { return f < y.f; } }edges[300300]; struct abcd{ int to,f,next; }table[M<<1]; int head[M],tot; int n,m,fa[M][20],f_max[M][20],f_2th_max[M][20],dpt[M]; ll ans_min,ans_2th_min=~0ull>>1; int belong[M]; int find(int x) { if(!belong[x]||belong[x]==x) return belong[x]=x; return belong[x]=find(belong[x]); } void add(int x,int y,int z) { table[++tot].to=y; table[tot].f=z; table[tot].next=head[x]; head[x]=tot; } void dfs(int x) { int i; dpt[x]=dpt[fa[x][0]]+1; for(i=head[x];i;i=table[i].next) { if(table[i].to==fa[x][0]) continue; fa[table[i].to][0]=x; f_max[table[i].to][0]=table[i].f; dfs(table[i].to); } } int Find_F_Max(int x,int y) { int j,re=0; if(dpt[x]<dpt[y]) swap(x,y); for(j=19;~j;j--) if(dpt[fa[x][j]]>=dpt[y]) re=max(re,f_max[x][j]),x=fa[x][j]; if(x==y) return re; for(j=19;~j;j--) if(fa[x][j]!=fa[y][j]) { re=max(re,f_max[x][j]); re=max(re,f_max[y][j]); x=fa[x][j]; y=fa[y][j]; } re=max(re,f_max[x][0]); re=max(re,f_max[y][0]); return re; } int Find_F_2th_Max(int x,int y,int z) { int j,re=0; if(dpt[x]<dpt[y]) swap(x,y); for(j=19;~j;j--) if(dpt[fa[x][j]]>=dpt[y]) { if(f_max[x][j]!=z) re=max(re,f_max[x][j]); else re=max(re,f_2th_max[x][j]); x=fa[x][j]; } if(x==y) return re; for(j=19;~j;j--) if(fa[x][j]!=fa[y][j]) { if(f_max[x][j]!=z) re=max(re,f_max[x][j]); else re=max(re,f_2th_max[x][j]); if(f_max[y][j]!=z) re=max(re,f_max[y][j]); else re=max(re,f_2th_max[y][j]); x=fa[x][j]; y=fa[y][j]; } j=0; if(f_max[x][j]!=z) re=max(re,f_max[x][j]); else re=max(re,f_2th_max[x][j]); if(f_max[y][j]!=z) re=max(re,f_max[y][j]); else re=max(re,f_2th_max[y][j]); return re; } int main() { int i,j; cin>>n>>m; for(i=1;i<=m;i++) scanf("%d%d%d",&edges[i].x,&edges[i].y,&edges[i].f); sort(edges+1,edges+m+1); for(i=1;i<=m;i++) { int fx=find(edges[i].x),fy=find(edges[i].y); if(fx!=fy) { edges[i].used=true; belong[fx]=fy; ans_min+=edges[i].f; add(edges[i].x,edges[i].y,edges[i].f); add(edges[i].y,edges[i].x,edges[i].f); } } dfs(1); for(j=1;j<=19;j++) for(i=1;i<=n;i++) { int f=fa[i][j-1]; fa[i][j]=fa[f][j-1]; if( f_max[i][j-1] > f_max[f][j-1] ) { f_max[i][j]=f_max[i][j-1]; f_2th_max[i][j]=max( f_2th_max[i][j-1] , f_max[f][j-1] ); } else { f_max[i][j]=f_max[f][j-1]; if( f_max[i][j-1] < f_max[f][j-1] ) f_2th_max[i][j]=max( f_2th_max[f][j-1] , f_max[i][j-1] ); else f_2th_max[i][j]=max( f_2th_max[i][j-1] , f_2th_max[f][j-1] ); } f_max[i][j]=max( f_max[i][j-1] , f_max[f][j-1] ); } for(i=1;i<=m;i++) if(!edges[i].used) { int temp=Find_F_Max(edges[i].x,edges[i].y); if(temp==edges[i].f) temp=Find_F_2th_Max(edges[i].x,edges[i].y,temp); ans_2th_min=min(ans_2th_min,ans_min-temp+edges[i].f); } cout<<ans_2th_min<<endl; }