jzoj 4769. 【GDOI2017模拟9.9】graph

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;
}
posted @ 2019-03-20 21:22  jz929  阅读(134)  评论(0编辑  收藏  举报