可以用并查集维护连通性,删除可以用按置合并并查集,但删掉一条边后无法再维护两点的联通性了(因为产生环的边是不加入的)
暴力思路是, 考虑前i个操作后边的集合,暴力加入即可,但复杂度是$o(n^2)$的
用分块,对于每一个块,先求出前面所有块操作后边的集合,去掉这个块内删掉的边,这个并查集一定是之后这个块内每一个点都有的并查集,即计算每一个点时都恢复到这个并查集(恢复时记录下修改的点,因此也不能路径压缩)
之后用暴力的做法,这个集合大小是$o(sqrt{n})$的,那么总复杂度就是$o(nsqrt{n})$,可以通过
(这个算法是离线,因为它需要之后那个块内的操作,但这些操作最多只会衍生出两种操作,只要存在一个就都不要放入原并查集中即可)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define K 5000 4 #define N 200005 5 #define pii pair<int,int> 6 #define fi first 7 #define se second 8 int n,m,ans,p[N],x[N],y[N],f[N],g[N],sz[N],v1[N]; 9 pii v2[N]; 10 set<pii>g1,g2; 11 set<pii>::iterator it; 12 int find(int k){ 13 if (k==f[k])return k; 14 return find(f[k]); 15 } 16 void check(int x,int y){ 17 if (x>y)swap(x,y); 18 pii o=make_pair(x,y); 19 if (g1.find(o)!=g1.end()){ 20 g1.erase(o); 21 g2.insert(o); 22 } 23 } 24 void update(pii o){ 25 if (g2.find(o)==g2.end())g2.insert(o); 26 else g2.erase(o); 27 } 28 void add(int x,int y){ 29 x=find(x); 30 y=find(y); 31 if (x==y)return; 32 if (sz[x]<sz[y])swap(x,y); 33 v1[++v1[0]]=y; 34 f[y]=x; 35 v2[v1[0]]=make_pair(x,sz[x]); 36 sz[x]=max(sz[x],sz[y]+1); 37 } 38 int main(){ 39 scanf("%d%d",&n,&m); 40 for(int i=1;i<=m;i++)scanf("%d%d%d",&p[i],&x[i],&y[i]); 41 for(int i=1;i<=m;i+=K){ 42 int k=min(m,i+K-1); 43 g2.clear(); 44 for(int j=i;j<=k;j++) 45 if (p[j]==1){ 46 check(x[j],y[j]); 47 check(x[j]%n+1,y[j]%n+1); 48 } 49 for(int j=1;j<=n;j++)f[j]=j; 50 for(it=g1.begin();it!=g1.end();it++)add((*it).fi,(*it).se); 51 v1[0]=0; 52 for(int j=i;j<=k;j++){ 53 x[j]=(x[j]+ans-1)%n+1; 54 y[j]=(y[j]+ans-1)%n+1; 55 if (x[j]>y[j])swap(x[j],y[j]); 56 if (p[j]==1)update(make_pair(x[j],y[j])); 57 else{ 58 for(int l=1;l<=v1[0];l++){ 59 f[v1[l]]=v1[l]; 60 sz[v2[l].fi]=v2[l].se; 61 } 62 v1[0]=0; 63 for(it=g2.begin();it!=g2.end();it++)add((*it).fi,(*it).se); 64 printf("%d",ans=(find(x[j])==find(y[j]))); 65 } 66 } 67 for(it=g2.begin();it!=g2.end();it++)g1.insert(*it); 68 } 69 }