• 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;
    }
    
    转载需注明出处。
  • 相关阅读:
    C++getline()
    Financial Tsunami
    Exploring Matrix
    shuffle.java
    Java数组声明
    jpg与jpeg的区别在哪
    WinForm训练一_改变窗体大小
    ErrorProvider与CheckedListBox
    如何看待 SAE 在2014 年 3 月 24 日发生的的大面积宕机事故?
    一个技术青年的网络失足
  • 原文地址:https://www.cnblogs.com/jz929/p/11817548.html
Copyright © 2020-2023  润新知