2 二分图 【题意描述】一个无向图被称为二分图当且仅当这个图中没有长度为奇数的环。给你一个包含 n 个点的图,这个图中一开始没有边。要求支持两种操作:在这个图中加入一条边。删除最后加入的边。每个操作之后需要判断这个图是否是二分图,如果是输出“ YES”,否则输出“ NO” 【输入格式】第一行包含两个整数 n 和 m,表示点数和询问数。接下来 m 行每行包含一个询问,格式如下: 1 x y(表示加入一条连接 x 和 y 的边) 2(表示删除最后加入的边) 【输出格式】输出共 m 行,每行包含一个字符串“ YES”或者一个字符串“ NO” 【样例输入】 3 3 1 1 2 1 2 3 1 3 1 【样例输出】 YES YES NO 【数据规模与约定】对于 80%的数据, n<=100,m<=3000。对于额外 15%的数据,没有第二种操作。对于 100%的数据,n<=10000,m<=1000000。 本题的做法是伪并查集,即在find()时不要路径压缩,具体细节见代码。#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; const int maxn=10010; int n,m; int cnt; int fa[maxn],st[maxn*100][2],front[maxn],vis[maxn]; int find(int x){ if(x==fa[x]) return x; else return find(fa[x]); } void link(int x,int y){ x=find(x);y=find(y); if(x==y){ st[++cnt][0]=-1; return; } fa[x]=y; st[++cnt][0]=x; st[cnt][1]=y; } void pop(){ if(st[cnt][0]==-1){ cnt--; return; } int x=st[cnt][0]; int y=st[cnt][1]; fa[x]=x; cnt--; } bool together(int x,int y){ return find(x)==find(y); } int main(){ scanf("%d%d",&n,&m); int i,j,k; for(i=1;i<=n*2;i++) fa[i]=i; int last=0; for(int kase=1;kase<=m;kase++){ int op; scanf("%d",&op); if(op==1){ int x,y; scanf("%d%d",&x,&y); front[kase]=last; if(vis[last]==1) vis[kase]=1; else if(together(x+n,y+n) || together(x,y)) vis[kase]=1; else{ link(x,y+n); link(x+n,y); } last=kase; if(vis[last]) printf("NO\n"); else printf("YES\n"); }else{ if(vis[last]==0){ pop();pop(); } last=front[last]; if(vis[last]) printf("NO\n"); else printf("YES\n"); } } return 0; }