BZOJ3237: [Ahoi2013]连通图
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3237
cdq分治+缩点。
可以每次处理的时候把除l~r之外的边的端点都连起来。然后去跑cdq分治。
当l==r的时候让那些修改边不连然后跑一边并查集。
#include<cstring> #include<iostream> #include<algorithm> #include<cstdio> #define rep(i,l,r) for (int i=l;i<=r;i++) #define down(i,l,r) for (int i=l;i>=r;i--) #define clr(x,y) memset(x,y,sizeof(x)) #define maxn 200500 using namespace std; struct data{int x,y,id,k,b; }a[21][maxn]; int b[maxn][5]; int fa[maxn],np[maxn],pos[maxn],n,m,Q; int read(){ int x=0,f=1; char ch=getchar(); while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();} while (isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();} return x*f; } int find(int x){ if (fa[x]==x) return x; return fa[x]=find(fa[x]); } void cdq(int dep,int l,int r,int n,int m){ rep(i,1,m){ data &c=a[dep][i],&c2=a[dep-1][i]; c=(data){c2.x,c2.y,c2.id,0,0}; pos[c2.id]=i; } if (l==r){ rep(i,1,b[l][0]) a[dep][pos[b[l][i]]].b=1; rep(i,1,n) fa[i]=i; int cnt=0; rep(i,1,m) if (a[dep][i].b!=1) { data c=a[dep][i]; int x=find(c.x),y=find(c.y); if (x!=y) fa[x]=y,cnt++; } if (cnt==n-1) puts("Connected"); else puts("Disconnected"); return; } rep(i,l,r) rep(j,1,b[i][0]) a[dep][pos[b[i][j]]].k=1; rep(i,1,n) fa[i]=i; rep(i,1,m) if (a[dep][i].k==0){ data &c=a[dep][i]; int x=find(c.x),y=find(c.y); if (x!=y) fa[x]=y; } rep(i,1,n) np[i]=0; int nn=0,nm=0; rep(i,1,n) if (!np[find(i)]) np[find(i)]=++nn; rep(i,1,m) if (a[dep][i].k) { data c=a[dep][i]; int x=find(c.x),y=find(c.y); a[dep][++nm]=(data){np[x],np[y],c.id,c.k,0}; } int mid=(l+r)/2; cdq(dep+1,l,mid,nn,nm); cdq(dep+1,mid+1,r,nn,nm); } int main(){ n=read(); m=read(); int x,y; rep(i,1,m){ x=read(); y=read(); a[0][i]=(data){x,y,i,0,0}; } Q=read(); rep(i,1,Q){ b[i][0]=read(); rep(j,1,b[i][0]) b[i][j]=read(); } cdq(1,1,Q,n,m); return 0; }