码迷,mamicode.com
首页 > 其他好文 > 详细

[bzoj4025]二分图_LCT

时间:2018-07-31 23:42:32      阅读:209      评论:0      收藏:0      [点我收藏+]

标签:span   集合   update   split   clu   void   flag   space   stat   

二分图 bzoj-4025

题目大意:给定一个n个节点的图,m条边,每条边有一个产生时间和一个删除时间,询问所有时间点是否是连通图。

注释:$1\le n\le 10^5$,$1\le m\le 2\cdot 10^5$


想法:好难...

又是一道结论题。开始不知道结论,在那里LCT不知道怎么判二分图... ...

其实就是判每一个时刻有没有奇环... ...硬核题...

紧接着,我们考虑如何维护。

我们先随便弄出一棵生成树,然后我们想维护这样的集合S。S中的任意一条边都会和生成树构成奇环。

有一种情况我们没有办法处理,就是把集合的边加上,然后... ...树边没了,我们还要把集合中的边换成树边,非常麻烦,码量堪忧。

所以,我们要维护最大删除时间生成树,就不会出现以上情况。

最后,附上丑陋的代码... ...

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ls ch[p][0]
#define rs ch[p][1]
#define get(x) (ch[f[x]][1]==x)
#define N 100010
using namespace std;
struct Node
{
	int x,y,t1,t2;
}a[N<<1];
int n,f[N<<2],ch[N<<2][2],size[N<<2],w[N<<2],mp[N<<2],rev[N<<2],num[N];
int sum,now;
inline char nc()
{
	static char buf[100000],*p1,*p2;
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
	int ret=0; char ch=nc();
	while(!isdigit(ch)) ch=nc();
	while(isdigit(ch)) ret=(ret<<3)+(ret<<1)+ch-48,ch=nc();
	return ret;
}
inline bool cmp(const Node &a,const Node &b)
{
	return a.t1<b.t1;
}
inline void pushup(int p)
{
	size[p]=size[ls]+size[rs]+1;
	mp[p]=p;
	if(w[mp[ls]]<w[mp[p]]) mp[p]=mp[ls];
	if(w[mp[rs]]<w[mp[p]]) mp[p]=mp[rs];
}
inline void pushdown(int p)
{
	if(!rev[p]) return;
	swap(ch[ls][0],ch[ls][1]); swap(ch[rs][0],ch[rs][1]);
	rev[ls]^=1; rev[rs]^=1; rev[p]=0;
}
inline bool isroot(int p)
{
	return ch[f[p]][0]!=p&&ch[f[p]][1]!=p;
}
void update(int p)
{
	if(!isroot(p)) update(f[p]);
	pushdown(p);
}
void rotate(int x)
{
	int y=f[x],z=f[y],k=get(x);
	if(!isroot(y)) ch[z][ch[z][1]==y]=x;
	ch[y][k]=ch[x][!k]; f[ch[y][k]]=y;
	ch[x][!k]=y; f[y]=x; f[x]=z;
	pushup(y); pushup(x);
}
void splay(int x)
{
	update(x);
	for(int t;t=f[x],!isroot(x);rotate(x))
	{
		if(!isroot(t)) rotate(get(x)==get(t)?t:x);
	}
}
void access(int p)
{
	int t=0;
	while(p) splay(p),rs=t,pushup(p),t=p,p=f[p];
}
int find(int p)
{
	access(p),splay(p);
	while(ls) pushdown(p),p=ls;
	return p;
}
inline void makeroot(int p)
{
	access(p),splay(p);
	swap(ls,rs),rev[p]^=1;
}
inline void link(int x,int y)
{
	makeroot(x),f[x]=y;
}
inline void cut(int x,int p)
{
	makeroot(x),access(p),splay(p);
	f[x]=ls=0;pushup(p);
}
inline void split(int x,int y)
{
	makeroot(x),access(y),splay(y);
}
void add(int p)
{
	int tx=a[p].x,ty=a[p].y,tmp,flag=0;
	if(tx==ty&&a[p].t2>now) num[a[p].t2]++,sum++;
	else
	{
		if(find(tx)!=find(ty)) link(p+n,tx),link(ty,p+n);
		else
		{
			split(tx,ty);
			if(!((size[ty]>>1)&1)) flag=1;
			if(w[mp[ty]]>=a[p].t2) tmp=p;
			else tmp=mp[ty]-n,cut(tmp+n,a[tmp].x),cut(tmp+n,a[tmp].y),link(p+n,tx),link(p+n,ty);
			if(flag&&a[tmp].t2>now) num[a[tmp].t2]++,sum++;
		}
	}
}
int main()
{
	int m,t,p=1;
	n=read(),m=read(),t=read();
	for(int i=1;i<=m;i++) a[i].x=read(),a[i].y=read(),a[i].t1=read(),a[i].t2=read();
	sort(a+1,a+m+1,cmp);
	for(int i=1;i<=n+m;i++) size[i]=1,mp[i]=i;
	for(int i=0;i<=n;i++) w[i]=1<<30;
	for(int i=1;i<=m;i++) w[i+n]=a[i].t2;
	for(int i=0;i<t;i++)
	{
		now=i;
		while(p<=m&&a[p].t1<=i) add(p),p++;
		sum-=num[i];
		if(sum) puts("No");
		else puts("Yes");
	}
	return 0;
}

小结:LCT就是强。

[bzoj4025]二分图_LCT

标签:span   集合   update   split   clu   void   flag   space   stat   

原文地址:https://www.cnblogs.com/ShuraK/p/9398638.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!