【题意】一个图为二分图当且仅当图中不存在边数为奇数的环。两种操作,1 x,y加入一条边,2删去最后加入的边,每次操作判断该图是否为二分图。
【思路】并查集判二分图
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#define maxn 1000006
using namespace std;
struct data{
int u1,f1,dp1,u2,f2,dp2;
data(int u1=0,int f1=0,int u2=0,int f2=0):u1(u1),f1(f1),dp1(dp1),u2(u2),f2(f2),dp2(dp2){};
}lin[maxn];
struct node{
int v1,v2,dp1,dp2;
node(int v1=0,int dp1=0,int v2=0,int dp2=0):v1(v1),dp1(dp1),v2(v2),dp2(dp2){};
}e[maxn];
int n,m,lst[maxn],da[10004<<1],dep[10004<<1];
bool f[maxn];
int get(){
char c;while(!isdigit(c=getchar()));
int v=c-48;while(isdigit(c=getchar()))v=v*10+c-48;
return v;
}
int getfa(int x){while(da[x]!=x) x=da[x];return x;}
void add(int x,int y,int num){
int a=getfa(x),b=getfa(y+n);
if(dep[a]>dep[b])swap(a,b);
int c=getfa(x+n),d=getfa(y);
if(dep[c]>dep[d])swap(c,d);
lin[num]=data(a,da[a],c,da[c]);
e[num]=node(b,dep[b],d,dep[d]);
da[a]=b;da[c]=d;
if(dep[a]==dep[b])++dep[b];
if(dep[c]==dep[d])++dep[d];
}
void del(int num){
da[lin[num].u1]=lin[num].f1;
dep[e[num].v1]=e[num].dp1;
da[lin[num].u2]=lin[num].f2;
dep[e[num].v2]=e[num].dp2;
}
void init(){
int x,y,z,now;
n=get();m=get();
f[now=0]=1;
for(int i=1;i<=(n<<1);++i)da[i]=i,dep[i]=1;
for(int k=1;k<=m;++k){
z=get();
if(z==1){
lst[k]=now;now=k;
x=get();y=get();
if(getfa(x)==getfa(y))f[now]=0;
else{
add(x,y,now);
f[now]=f[lst[now]];
}
}
else{
del(now);
now=lst[now];
}
if(f[now])printf("YES\n");
else printf("NO\n");
}
}
int main(){
init();
return 0;
}
【注意】
1、要有并查集的删除操作,即记录每次加边前x,y结点的集合和深度。
2、深度小的连到深度大的可加快速度。
3、x与y+n连边,y与x+n连边,若出现两点在同一集合则不是二分图。