BZOJ4025 二分图

原题链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4025

二分图

Description

神犇有一个n个节点的图。因为神犇是神犇,所以在T时间内一些边会出现后消失。神犇要求出每一时间段内这个图是否是二分图。这么简单的问题神犇当然会做了,于是他想考考你。

Input

输入数据的第一行是三个整数n,m,T。

第2行到第m+1行,每行4个整数u,v,start,end。第i+1行的四个整数表示第i条边连接u,v两个点,这条边在start时刻出现,在第end时刻消失。

Output

输出包含T行。在第i行中,如果第i时间段内这个图是二分图,那么输出“Yes”,否则输出“No”,不含引号。

Sample Input

3 3 3
1 2 0 2
2 3 0 3
1 3 1 2

Sample Output

Yes
No
Yes

HINT
样例说明:

0时刻,出现两条边1-2和2-3。

第1时间段内,这个图是二分图,输出Yes。

1时刻,出现一条边1-3。

第2时间段内,这个图不是二分图,输出No。

2时刻,1-2和1-3两条边消失。

第3时间段内,只有一条边2-3,这个图是二分图,输出Yes。

数据范围:

n<=100000,m<=200000,T<=100000,1<=u,v<=n,0<=start<=end<=T。

题解

偶然发现一篇咕咕咕了多年的题解,顺手水一波。

这么好的题当然要用 L C T \mathcal{LCT} LCT,把出现一条边看做 l i n k link link,消失看做 c u t cut cut,按时间将操作离线,如果出现了奇环,这就是个二分图。

但是这是个图, L C T \mathcal{LCT} LCT总有 l i n k link link出环的时候,所以我们只在 L C T \mathcal{LCT} LCT中保存一个以删除时间为关键值的最大生成树, l i n k link link时如果出现了环,将删除时间最早的边从 L C T \mathcal{LCT} LCT中删去,如果形成的是奇环,还要进行标记,奇环数 + 1 +1 +1

删除时,如果该边本来就在 L C T \mathcal{LCT} LCT里,直接删去。如果不在 L C T \mathcal{LCT} LCT里且为我们标记过的奇环边,去掉标记,奇环数 − 1 -1 1

在本时间点的操作全部做完以后,根据奇环数回答询问即可。

代码
#include<bits/stdc++.h>
#define ls son[v][0]
#define rs son[v][1]
using namespace std;
const int M=1e6+5;
struct sd{int op,a1,a2,t,id;};
struct ed{int a1,a2,t;};
bool operator <(sd a,sd b){return a.t<b.t;}
int dad[M],son[M][2],siz[M],mn[M],val[M],n,m,t,top,ans;
bool rev[M],gg[M],on[M];sd ope[M];ed edge[M];
bool notroot(int v){return son[dad[v]][1]==v||son[dad[v]][0]==v;}
void up(int v)
{
	siz[v]=(v>n)+siz[ls]+siz[rs];mn[v]=v;
	if(val[mn[v]]>val[mn[ls]])mn[v]=mn[ls];  
	if(val[mn[v]]>val[mn[rs]])mn[v]=mn[rs];
}
void turn(int v){swap(ls,rs);rev[v]^=1;}
void down(int v){if(!rev[v])return;if(ls)turn(ls);if(rs)turn(rs);rev[v]=0;}
void push(int v){if(notroot(v))push(dad[v]);down(v);}
void spin(int v)
{
	int f=dad[v],ff=dad[f],k=son[f][1]==v,w=son[v][!k];
	if(notroot(f))son[ff][son[ff][1]==f]=v;son[v][!k]=f,son[f][k]=w;if(w)dad[w]=f;dad[f]=v,dad[v]=ff;
	up(f);
}
void splay(int v){push(v);for(int f,ff;notroot(v);spin(v)){f=dad[v],ff=dad[f];if(notroot(f))spin((son[f][0]==v)^(son[ff][0]==f)?v:f);}up(v);}
void access(int v){for(int f=0;v;v=dad[f=v])splay(v),rs=f,up(v);}
void beroot(int v){access(v);splay(v);turn(v);}
void split(int x,int y){beroot(x);access(y);splay(y);}
void link(int x,int y){beroot(x);dad[x]=y;}
void cut(int x,int y){split(x,y);dad[x]=son[y][0]=0;up(y);}
int findroot(int v){access(v);splay(v);while(ls)push(v),v=ls;return v;}
void in()
{
	int a,b,c,d,i;
	for(scanf("%d%d%d",&n,&m,&t),memset(val,127,sizeof(val)),i=1;i<=m;++i)
	scanf("%d%d%d%d",&a,&b,&c,&d),val[n+i]=d,ope[++top]=(sd){0,a,b,c,i},ope[++top]=(sd){1,a,b,d,i},edge[i]=(ed){a,b,d};
}
void deal1(int x,int y,int id,int lim)
{
	int hh;
	if(x==y){ans++;gg[id]=1;return;}
	beroot(x);
	if(findroot(y)!=x){link(y,id+n);link(x,id+n);on[id]=1;return;}
	else
	{
		split(x,y);
		if(val[mn[y]]<lim)
		{
			hh=mn[y]-n;
			if(siz[y]&1^1)gg[hh]=1,ans++;
			cut(edge[hh].a1,hh+n);cut(edge[hh].a2,hh+n);link(x,id+n);link(y,id+n);
			on[hh]=0;on[id]=1;
		}
		else if(siz[y]&1^1)gg[id]=1,ans++;
	}
}
void deal2(int x,int y,int id){if(on[id])cut(x,id+n),cut(y,id+n),on[id]=0;else if(gg[id])gg[id]=0,ans--;}
void ac()
{
	sort(ope+1,ope+1+top);
	for(int i=0,j=1,x,y,id;i<t;ans?puts("No"):puts("Yes"))
	for(++i;ope[j].t<i&&j<=top;++j){x=ope[j].a1,y=ope[j].a2,id=ope[j].id;ope[j].op?deal2(x,y,id):deal1(x,y,id,edge[id].t);}
}
int main(){in();ac();}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShadyPi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值