#分塊,可撤銷並查集#洛谷 5443 [APIO2019]橋樑
阿新 • • 發佈:2022-02-23
分塊,可撤銷並查集
分析
最直接的做法就是線上一邊修改邊權,詢問直接全部重排,
然後用可撤銷並查集維護連通塊大小,這樣時間複雜度為 \(O(qm)\)
同樣儘量讓大部分的邊不需要修改邊權,那麼每 \(B\) 個操作整體進行一次,
那麼最多隻有 \(B\) 條邊會修改,剩下的邊直接用雙指標加入並查集。
這 \(B\) 條邊直接每次詢問修改邊權,然後排序加入並查集,詢問完與剩下的邊歸併排序
那麼時間複雜度為 \(O(qB\log n+\frac{m^2}{B}\log n)\),實際上 \(B\) 取 \(\sqrt{m\log n}\) 跑得比較快。
注意可撤銷並查集不能通過siz的大小合併,只是為了方便,但可能會被卡。
程式碼
#include <cstdio> #include <cctype> #include <algorithm> #include <cmath> using namespace std; const int N=100011; struct node{int x,y,w;}e[N]; struct rec{int x,y,rk;}q[N],a[N]; int n,m,Q,bl,f[N],rk[N],siz[N],ans[N],Fa[N],tod,Fb[N],v[N],Rk[N],RK[N],rK[N]; 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(int ans){ if (ans>9) print(ans/10); putchar(ans%10+48); } bool cmp0(int x,int y){return e[x].w>e[y].w;} bool cmp1(int x,int y){return q[x].y>q[y].y;} int getf(int u){return f[u]==u?u:getf(f[u]);} void Merge(int x,int y){ int fa=getf(x),fb=getf(y); if (siz[fa]>siz[fb]) swap(fa,fb); if (fa==fb) return; f[fa]=fb,siz[fb]+=siz[fa],Fa[++tod]=fa,Fb[tod]=fb; } int main(){ n=iut(),m=iut(); for (int i=1;i<=m;++i) e[i]=(node){iut(),iut(),iut()}; for (int i=1;i<=n;++i) f[i]=i,siz[i]=1; for (int i=1;i<=m;++i) rk[i]=i; Q=iut(),bl=sqrt(m*log(n)),sort(rk+1,rk+1+m,cmp0); for (int l=1,r;l<=Q;l+=bl){ if (l+bl>Q) r=Q; else r=l+bl-1; int tot=0,cnt=0,TOT=0,ToT=0; for (int i=l;i<=r;++i){ int opt=iut(),x=iut(),y=iut(); if (opt==1) ++tot,a[tot]=(rec){x,y,tot},v[x]=l; else q[++cnt]=(rec){x,y,tot},Rk[cnt]=cnt; } if (!cnt) continue; for (int i=1;i<=m;++i) if (v[i]==l) rK[++TOT]=i; sort(Rk+1,Rk+1+cnt,cmp1); for (int i=1,j=1;i<=cnt;++i){ for (;j<=m&&e[rk[j]].w>=q[Rk[i]].y;++j) if (v[rk[j]]!=l) Merge(e[rk[j]].x,e[rk[j]].y); for (int k=1;k<=q[Rk[i]].rk;++k) swap(e[a[k].x].w,a[k].y); int Tod=tod; for (int k=1;k<=TOT;++k) if (e[rK[k]].w>=q[Rk[i]].y) Merge(e[rK[k]].x,e[rK[k]].y); ans[Rk[i]]=siz[getf(q[Rk[i]].x)]; for (;tod>Tod;--tod) siz[Fb[tod]]-=siz[Fa[tod]],f[Fa[tod]]=Fa[tod]; for (int k=q[Rk[i]].rk;k;--k) swap(e[a[k].x].w,a[k].y); } for (;tod;--tod) siz[Fb[tod]]-=siz[Fa[tod]],f[Fa[tod]]=Fa[tod]; for (int k=1;k<=tot;++k) swap(e[a[k].x].w,a[k].y); sort(rK+1,rK+1+TOT,cmp0); int I=1,J=1; while (I<=TOT){ while (J<=m&&v[rk[J]]==l) ++J; if (J<=m&&e[rk[J]].w>=e[rK[I]].w) RK[++ToT]=rk[J++]; else RK[++ToT]=rK[I++]; } for (;J<=m;++J) if (v[rk[J]]!=l) RK[++ToT]=rk[J]; for (int i=1;i<=ToT;++i) rk[i]=RK[i]; for (int i=1;i<=cnt;++i) print(ans[i]),putchar(10); } return 0; }