#分治,Kruskal#洛谷 3206 [HNOI2010]城市建設
阿新 • • 發佈:2022-02-17
分治,Kruskal
同級
題目
動態改邊權求最小生成樹
\(n\leq 2*10^4,m\leq 5*10^4,q\leq 5*10^4\)
分析
乍一看是線段樹分治,但有一個很大的問題就是區域性的Kruskal不一定是最後的選擇,
但是如果在底部再處理所有邊的話,那仍然是 \(O(qm\log m)\) 的複雜度,必須在到達底層之前處理掉一些邊。
由於所有邊只是邊權改變,並不需要線段樹分治(常數會更大)。
分治到 \([l,r]\) 區間時,考慮兩種特殊情況,就是需要修改的邊無限大或者無限小。
無限小的時候,如果其它邊被選上了,那麼它們在之後肯定也會被選上,
直接縮成同一個連通塊並統計答案,這樣就保證點數一定與 \(r-l\)
無限大的時候,如果沒有被選上,一定不會被選上,直接不管這些邊。
各跑一次Kruskal,時間複雜度 \(O(m\log q\log m)\)
程式碼
#include <cstdio> #include <cctype> #include <algorithm> using namespace std; const int N=50011,inf=1e9; typedef long long lll; struct rec{int x,w;}q[N]; struct node{int x,y,w,rk;}e[21][N],E[N]; int edge[21],w[N],rk[N],f[N],b[N],n,m,Q; lll ans[21]; int iut(){ int ans=0; char c=getchar(); while (!isdigit(c)) c=getchar(); while (isdigit(c)) ans=ans*10+c-48,c=getchar(); return ans; } void print(lll ans){ if (ans>9) print(ans/10); putchar(ans%10+48); } bool cmp(node x,node y){return x.w<y.w;} int getf(int u){return f[u]==u?u:f[u]=getf(f[u]);} void dfs(int dep,int l,int r){ int Edge=edge[dep]; lll Ans=ans[dep]; if (l==r) w[q[l].x]=q[l].w; for (int i=1;i<=Edge;++i){ e[dep][i].w=w[e[dep][i].rk]; E[i]=e[dep][i],rk[E[i].rk]=i; } if (l==r){ sort(E+1,E+1+Edge,cmp); for (int i=1;i<=Edge;++i) f[E[i].x]=E[i].x,f[E[i].y]=E[i].y; for (int i=1;i<=Edge;++i){ int fa=getf(E[i].x),fb=getf(E[i].y); if (fa>fb) fa^=fb,fb^=fa,fa^=fb; if (fa!=fb) Ans+=E[i].w,f[fa]=fb; } print(Ans),putchar(10); return; } for (int i=l;i<=r;++i) E[rk[q[i].x]].w=-inf; for (int i=1;i<=Edge;++i) f[E[i].x]=E[i].x,f[E[i].y]=E[i].y; sort(E+1,E+1+Edge,cmp); int EDGE=0; for (int i=1;i<=Edge;++i){ int fa=getf(E[i].x),fb=getf(E[i].y); if (fa>fb) fa^=fb,fb^=fa,fa^=fb; if (fa!=fb) f[fa]=fb,b[++EDGE]=i; } for (int i=1;i<=EDGE;++i) f[E[b[i]].x]=E[b[i]].x,f[E[b[i]].y]=E[b[i]].y; for (int i=1;i<=EDGE;++i) if (E[b[i]].w!=-inf){ int fa=getf(E[b[i]].x),fb=getf(E[b[i]].y); if (fa>fb) fa^=fb,fb^=fa,fa^=fb; Ans+=E[b[i]].w,f[fa]=fb; } EDGE=0; for (int i=1;i<=Edge;++i){ int fa=getf(E[i].x),fb=getf(E[i].y); if (fa!=fb) b[++EDGE]=i; } for (int i=1;i<=EDGE;++i){ E[i]=(node){f[E[b[i]].x],f[E[b[i]].y],E[b[i]].w,E[b[i]].rk}; rk[E[i].rk]=i; } Edge=EDGE; for (int i=l;i<=r;++i) E[rk[q[i].x]].w=inf; for (int i=1;i<=Edge;++i) f[E[i].x]=E[i].x,f[E[i].y]=E[i].y; sort(E+1,E+1+Edge,cmp),EDGE=0; for (int i=1;i<=Edge;++i){ int fa=getf(E[i].x),fb=getf(E[i].y); if (fa>fb) fa^=fb,fb^=fa,fa^=fb; if (fa!=fb) f[fa]=fb,b[++EDGE]=i; else if (E[i].w==inf) b[++EDGE]=i; } for (int i=1;i<=EDGE;++i){ E[i]=(node){E[b[i]].x,E[b[i]].y,E[b[i]].w,E[b[i]].rk}; rk[E[i].rk]=i; } Edge=EDGE; for (int i=1;i<=Edge;++i) e[dep+1][i]=E[i]; int mid=(l+r)>>1; edge[dep+1]=Edge,ans[dep+1]=Ans; dfs(dep+1,l,mid),dfs(dep+1,mid+1,r); } int main(){ n=iut(),m=iut(),Q=iut(); for (int i=1;i<=m;++i) e[0][i]=(node){iut(),iut(),w[i]=iut(),i}; for (int i=1;i<=Q;++i) q[i]=(rec){iut(),iut()}; edge[0]=m,dfs(0,1,Q); return 0; }