1. 程式人生 > 實用技巧 >「APIO2019」橋樑(詢問分塊+並查集)

「APIO2019」橋樑(詢問分塊+並查集)

「APIO2019」橋樑(詢問分塊+並查集)

詢問每\(S\)個分塊後,每次對於所有塊內未被更改的邊 及 所有詢問 排序,然後依次加入並查集,這一部分複雜度為\(O(m \frac{q}{S}(\log m+\alpha(n)))\)

對於\(S\)條被改變的邊,對於每個詢問分別考慮這些邊的貢獻,複雜度為\(O(qS)\),由於涉及到並查集回撤的問題,可以使用按秩合併,複雜度為\(O(qS\log S)\)

按照上面兩步暴力實現,複雜度大概可以做到\(O((m+q)\sqrt{q}\log n)\)

實際可行的優化有:

用平衡樹實現排序,每次暴力遍歷,第一部分複雜度降為\(O(q\log m+m\frac{q}{S} \alpha(n))\)

由於最多訪問到\(O(S)\)個聯通塊,第二部分用\(dfs\)遍歷來實現,複雜度降為\(O(q S \alpha(n))\)(遍歷過程中要訪問聯通塊編號)

複雜度可以降到約\(O((m+q)\sqrt {q} \cdot \alpha(n))\)

以下是暴力實現的程式碼

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
#define pb push_back
char IO;
int rd(){
	int s=0;
	while(!isdigit(IO=getchar()));
	do s=(s<<1)+(s<<3)+(IO^'0');
	while(isdigit(IO=getchar()));
	return s;
}

const int N=1e5+10;
int n,m,S,q,qc;
struct Edge{
	int u,v,w;
	bool operator < (Edge __) const { return w<__.w; }
} A[N],B[N],Q[N];
struct Node{ int t,w; };
vector <Node> G[N];
int uid[N],uc,fa[N],sz[N],ux[N],uy[N],rc,ans[N];
int Find(int x){ while(fa[x]!=x) x=fa[fa[x]]; return x; }
void Union(int x,int y){
	x=Find(x),y=Find(y);
	if(x==y) return;
	if(sz[x]>sz[y]) swap(x,y);
	ux[++rc]=x,uy[rc]=y;
	fa[x]=y,sz[y]+=sz[x]; // 按秩合併用於回撤
}

int main(){
	n=rd(),m=rd();
	rep(i,1,m) A[i].u=rd(),A[i].v=rd(),A[i].w=rd();
	S=sqrt(3*(n+m));
	rep(i,1,q=rd()) {
		ans[i]=-1;
		int opt=rd(),x=rd(),y=rd();
		if(opt==1) G[x].pb((Node){i,y});
		else Q[++qc]=(Edge){i,x,y};
		if(qc%S==0 || i==q) {
			if(!qc) continue;
			int c=0;
			rep(i,1,m) if(!G[i].size()) B[++c]=A[i];
			else uid[++uc]=i;
			sort(B+1,B+c+1),sort(Q+1,Q+qc+1);
			rep(i,1,n) fa[i]=i,sz[i]=1;
			int p=c;
			drep(i,qc,1) {
				while(p && B[p].w>=Q[i].w) Union(B[p].u,B[p].v),p--;
				rc=0;
				rep(j,1,uc) {
					int x=uid[j],w=A[x].w;
					for(auto k:G[x]) if(k.t<=Q[i].u) w=k.w;
					else break; // 找到詢問時這條邊的權值
					if(w>=Q[i].w) Union(A[x].u,A[x].v);
				}
				ans[Q[i].u]=sz[Find(Q[i].v)];
				drep(j,rc,1) fa[ux[j]]=ux[j],fa[uy[j]]=uy[j],sz[uy[j]]-=sz[ux[j]];// 回撤
				rc=0;
			}
			rep(i,1,uc) A[uid[i]].w=G[uid[i]].rbegin()->w,G[uid[i]].clear();
			uc=qc=0;
		}
	}
	rep(i,1,q) if(~ans[i]) printf("%d\n",ans[i]);
}