Description
对于一个图, 如果它的点集能被分成两个部分, 使得在原图中每一部分之间的点没有任何边相连,则该图被称为二分图。
现在给定一个无向图,每次增加一条边,或者删除一条边。要求您每次判断它是不是二分图。
Input
第一行两个数n,m,表示该图的点数和操作数。
接下来m行,以一个数type开头。type为0或1。若type为1则表示加一条边,接下来输入两个数a,b表示它连接的边的编号,编号从0到n-1;为0则表示删除一条边,接下来是一个数a表示删除加入的第a+1条边。
保证任何时候图都无重边或自环。
Output
m行,每行一个"YES"或"NO"(引号不输出),表示每次操作后图是否是二分图。
Sample Input
3 3
1 0 1
1 0 2
1 1 2
Sample Output
YES
YES
NO
Data Constraint
Solution
这题打得我要死要活的。。。
首先我们先分析一下题目描述,有加边操作也有删边操作,然后判断一下二分图。
手推一下就发现只有当图中有奇环的情况下才是NO。
所以题目就转化成:支持加边及删边,每次判奇环
我们发现在线操作好像不太可行,所以我们考虑离线。
我们发现,每一条边都有一定的存在时间,我们可以按照时间来搞一棵线段树,然后在一些节点上存一下边(前向星)。
之后,我们开始遍历这棵线段树(感觉好像CDQ分治啊QAQ)
我们用个按秩合并版的并查集来维护当前的边的状态。(记得存储一下每条边的长度)
每次经过一个节点,就暴力加边,退出时暴力删边。删边的话用个栈来暴力存一下之前的值以及边的两点即可。
到了叶子节点的时候,加完边而且没有奇环的话,便说明这个时间是YES,输出就可以了。
(小优化:如果到当前节点发现存在奇环,就说明整棵子树都是NO,直接输出并删边即可)
Code
#include<cstdio>
#include<algorithm>
#define N 300010
using namespace std;
struct node{int x,y,st,ed;}edge[N];
struct bian{int v,fr;}e[N<<3];
int rd[N][2],len[N],fa[N],lg[N],ad[N],bef[N<<2][3],t[N<<3];
int n,m,mi,oc=0,tot=0,tail[N<<3],cnt=0,bfnum=0;
inline int read()
{
int x=0; char c=getchar();
while (c<'0' || c>'9') c=getchar();
while (c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x;
}
//int gf(int x) {return !fa[x] ? x:gf(fa[x]);}
void add(int u,int v) {e[++cnt]=(bian){v,tail[u]}; tail[u]=cnt;}
void insert(int x,int l,int r,int line)
{
if (edge[line].st<=l && edge[line].ed>=r)
{
add(x,line);
return;
}
int mid=l+r>>1;
if (edge[line].st<=mid) insert(x<<1,l,mid,line);
if (edge[line].ed>mid) insert(x<<1|1,mid+1,r,line);
}
void solve(int x,int l,int r)
{
if (l==9 && r==10)
{
l=9,r=10;
}
int bf=bfnum;
for (int p=tail[x],v,fx,fy,lon;p;p=e[p].fr)
{
v=e[p].v,fx=edge[v].x,fy=edge[v].y;
lon=1;
while (fa[fx]) lon+=lg[fx],fx=fa[fx];
while (fa[fy]) lon+=lg[fy],fy=fa[fy];
if (fx!=fy)
{
if (len[fx]>len[fy]) swap(fx,fy);
fa[fx]=fy,lg[fx]=lon;
bef[++bfnum][0]=fy;
bef[bfnum][1]=len[fy];
bef[bfnum][2]=fx;
len[fy]=max(len[fy],len[fx]+1);
}
else
{
if (lon & 1)
{
for (int i=l;i<=r;i++) puts("NO");
while (bfnum>bf)
{
len[bef[bfnum][0]]=bef[bfnum][1];
fa[bef[bfnum][2]]=0;
bfnum--;
}
return;
}
}
}
if (l==r) puts("YES");
else
{
int mid=l+r>>1;
solve(x<<1,l,mid);
solve(x<<1|1,mid+1,r);
}
while (bfnum>bf)
{
len[bef[bfnum][0]]=bef[bfnum][1];
fa[bef[bfnum][2]]=0;lg[bef[bfnum][2]]=0;
bfnum--;
}
}
int main()
{
freopen("graph.in","r",stdin);
freopen("graph.out","w",stdout);
// find odd circle
n=read(),m=read();
for (int i=1,a,b;i<=m;i++)
{
rd[i][0]=read(),a=read()+1;
if (rd[i][0]==1) b=read()+1,edge[++tot]=(node){a,b,i,m},rd[i][1]=tot;
else edge[a].ed=i-1,rd[i][1]=a;
}
for (int i=1;i<=tot;i++)
insert(1,1,m,i);
solve(1,1,m);
return 0;
}