luogu P5787 二分图 /【模板】线段树分治

线段树分治真的难写。

二分图判定的条件是图中不存在奇环。我们可以用带权并查集来维护。现在的难点就在于对线段树\(DFS\)时回溯的时候如何删除影响。

这里可以使用可删并查集:注意到我们加入影响和删除影响的过程就是维护栈的过程,我们可以放弃并查集的路径压缩(我们按秩合并也可以保证复杂度),并在加入边时记录操作,并在删除时改回去。

  • 这题的一些细节:
  1. 当你发现加入一条边后已经不符合二分图的限制了,则你此后(到回溯前)的所有边都可以不用加了(显然)。
  2. 按秩合并就是你给每个块顺便记录一个大小,合并的时候把小的往大的里加,即可保证复杂度(类似于重链剖分的复杂度分析)。

啊啊啊说白了就是烦。

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stack>

using namespace std;

const int N=200009;
struct Node
{
	int first,second,ok,A,B;
};
int n,m,K,f[N],fuck[N],flag,flagk,flagp,siz[N];
vector <Node> b[N*4];

void Modify(int k,int l,int r,int x,int y,int p,int q)
{
	if(l>=x&&r<=y)
	{
		b[k].push_back((Node){p,q,0,0,0});
		return;
	}
	int mid=l+r>>1;
	if(mid>=x)
		Modify(k<<1,l,mid,x,y,p,q);
	if(mid<y)
		Modify(k<<1|1,mid+1,r,x,y,p,q);
}

int find(int x)
{
	if(x==f[x]) return x;
	return find(f[x]);
}

int Get_Dis(int x)
{
	if(x==f[x]) return 0;
	return fuck[x]^Get_Dis(f[x]);
}

void init()
{
	scanf("%d %d %d",&n,&m,&K);
	for (int i=1;i<=m;i++)
	{
		int x,y,s,t;
		scanf("%d %d %d %d",&x,&y,&s,&t);
		if(s==t) continue;
		Modify(1,1,K,s+1,t,x,y);
	}
	for (int i=1;i<=n;i++)
		f[i]=i,siz[i]=1;
}

void dfs(int k,int l,int r)
{
	if(!flag)
		for (int i=0;i<b[k].size();i++)
		{
			Node v=b[k][i];
			int x=v.first,y=v.second;
			int A=find(x),B=find(y);
			if(siz[A]<siz[B])
				swap(x,y),swap(A,B);
			if(A!=B)
			{
				siz[A]+=siz[B];
				f[B]=A,fuck[B]=Get_Dis(y)^Get_Dis(x)^1;
				b[k][i].ok=1,b[k][i].A=A,b[k][i].B=B;
			}
			else if(!(Get_Dis(x)^Get_Dis(y)))
			{
				flag=1;
				flagk=k;
				flagp=i;
				break;
			}
		}
	if(l==r)
		puts(flag?"No":"Yes");
	else
	{
		int mid=l+r>>1;
		dfs(k<<1,l,mid);
		dfs(k<<1|1,mid+1,r);
	}
	if(!flag)
	{
		for (int i=b[k].size()-1;i>=0;i--)
		{
			Node v=b[k][i];
			if(!v.ok)
				continue;
			f[v.B]=v.B,fuck[v.B]=0,siz[v.A]-=siz[v.B];
		}
	}
	else if(k==flagk)
	{
		flag=0;
		if(flagp==0) return;
		for (int i=flagp-1;i>=0;i--)
		{
			Node v=b[k][i];
			if(!v.ok)
				continue;
			f[v.B]=v.B,fuck[v.B]=0,siz[v.A]-=siz[v.B];
		}
	}
}

int main()
{
	init();
	dfs(1,1,K);
	return 0;
}
posted @ 2020-06-10 02:22  With_penguin  阅读(85)  评论(0编辑  收藏  举报