bzoj4025 二分图 lct

       显然一个图是二分图当且仅当图中不存在一个奇环。那么我们用lct维护一个树形结构,如果不存在一条非树边,它连接的两个点在树上的距离为偶数,那么就是一个二分图。那么我们按时间离线之后维护一个树形结构和一个边的集合,集合中的边连接的两点在树上的距离为偶数。那么这个集合为空集则为二分图。

       那么如果出现奇环,留下拿一条边在树上就成了问题。显然消失时间晚的可以存在的更久,因此维护一个消失时间的最大生成树(森林)即可。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 100005
#define M 300005
using namespace std;

int n,m,cnt,pt,b[M],c[M][2],val[M],sz[M],fa[M],q[M];
bool bo[N<<1],flag[N<<1],rev[M];
struct graph{
	int fst[N],nxt[N<<1];
	void add(int x,int y){
		nxt[y]=fst[x]; fst[x]=y;
	}
}g1,g2;
struct node{ int x,y; }a[N<<1];
int read(){
	int x=0; char ch=getchar();
	while (ch<'0' || ch>'9') ch=getchar();
	while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }
	return x;
}
bool isrt(int x){
	return c[fa[x]][0]!=x && c[fa[x]][1]!=x;
}
void maintain(int x){
	val[x]=x; sz[x]=(x>n)?1:0;
	if (c[x][0]){
		sz[x]+=sz[c[x][0]];
		if (b[val[c[x][0]]]<b[val[x]]) val[x]=val[c[x][0]];
	}
	if (c[x][1]){
		sz[x]+=sz[c[x][1]];
		if (b[val[c[x][1]]]<b[val[x]]) val[x]=val[c[x][1]];
	}
}
void rotate(int x){
	int y=fa[x],z=fa[y],l=(c[y][0]==x)?0:1,r=l^1;
	if (!isrt(y))
		if (c[z][0]==y) c[z][0]=x; else c[z][1]=x;
	fa[x]=z; fa[y]=x; fa[c[x][r]]=y;
	c[y][l]=c[x][r]; c[x][r]=y;
	maintain(y); maintain(x);
}
void pushdown(int x){
	if (rev[x]){
		swap(c[x][0],c[x][1]);
		rev[c[x][0]]^=1; rev[c[x][1]]^=1; rev[x]=0;
	}
}
void splay(int x){
	int y,z,i,tp=1; q[1]=x;
	for (i=x; !isrt(i); i=fa[i]) q[++tp]=fa[i];
	for (i=tp; i; i--) pushdown(q[i]);
	for (; !isrt(x); rotate(x)){
		y=fa[x]; z=fa[y];
		if (!isrt(y))
			if ((c[y][0]==x)^(c[z][0]==y)) rotate(x); else rotate(y);
	}
}
void acss(int x){
	int y=0;
	for (; x; y=x,x=fa[x]){
		splay(x); c[x][1]=y; maintain(x);
	}
}
void makert(int x){
	acss(x); splay(x); rev[x]^=1;
}
void link(int x,int y){
	makert(x); fa[x]=y;
}
void cut(int x,int y){
	makert(x); acss(y); splay(y); fa[x]=c[y][0]=0; maintain(y);
}
int findrt(int x){
	acss(x); splay(x);
	while (c[x][0]) x=c[x][0]; return x;
}
void ins(int x,int y,int z){
	int u=findrt(x),v=findrt(y);
	if (x==y){ pt++; flag[z]=1; return; }
	if (u!=v){
		bo[z]=1; link(x,z+n); link(y,z+n);
	} else{
		makert(x); acss(y); splay(y);
		u=val[y]-n;
		if (b[u+n]<b[z+n]){
			if (!(sz[y]&1)){ pt++; flag[u]=1; }
			cut(a[u].x,u+n); cut(a[u].y,u+n);
			link(x,z+n); link(y,z+n);
			bo[u]=0; bo[z]=1;
		} else if (!(sz[y]&1)){ pt++; flag[z]=1; }
	}
}
int main(){
	n=read(); m=read(); cnt=read(); int i,j;
	for (i=1; i<=n; i++){ val[i]=1; b[i]=1000000000; }
	for (i=1; i<=m; i++){
		a[i].x=read(); a[i].y=read();
		g1.add(read()+1,i); g2.add(b[i+n]=read()+1,i);
		sz[i+n]=1; val[i+n]=i+n;
	}
	for (i=1; i<=cnt; i++){
		for (j=g1.fst[i]; j; j=g1.nxt[j]) ins(a[j].x,a[j].y,j);
		for (j=g2.fst[i]; j; j=g2.nxt[j])
			if (bo[j]){ cut(a[j].x,j+n); cut(a[j].y,j+n); } else if (flag[j]) pt--;
		puts(pt?"No":"Yes");
	}
	return 0;
}

by lych

2016.5.2

你可能感兴趣的:(二分图,最大生成树,LCT)