• BZOJ4025: 二分图


    BZOJ4025: 二分图

    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。

    题解Here!

    又是一道神题,好难。。。

    开始的时候并不知道$LCT$怎么判二分图。。。

    然后翻题解。。。百度一下二分图。

    二分图就是在任意时刻,这个图中一定没有奇环。

    奇环是什么?就是有奇数个点的环啊。。。

    其实就是判每一个时刻有没有奇环。

    然后我们考虑如何维护。

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

    有一种情况我们没有办法处理,就是:把集合的边加上,然后,树边没了。。。

    我们还要把集合中的边换成树边,非常麻烦,码量贼大。。。

    所以我们维护以删除时间为边权的最大生成树,就可以解决以上这种情况了。

    然后就是$LCT$板子了,开始码码码。。。

    然后我一下午就这么搭进去了。。。

    据说还有分治+并查集的算法?反正本蒟蒻不会。。。

    orz POPOQQQ姐。

    附代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #define MAXN 400010
    #define MAX 2147483646
    using namespace std;
    int n,m,q,ans=0;
    int num[MAXN],val[MAXN];
    struct Edge{
    	int u,v,start,end;
    	friend bool operator <(const Edge &p,const Edge &q){
    		if(p.start==q.start)return p.end<q.end;
    		return p.start<q.start;
    	}
    }edge[MAXN];
    inline int read(){
    	int date=0,w=1;char c=0;
    	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
    	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
    	return date*w;
    }
    namespace LCT{
    	int top=0,stack[MAXN];
    	struct Link_Cut_Tree{
    		int f,flag,son[2];
    		int v,s;
    	}a[MAXN];
    	inline bool isroot(int rt){
    		return a[a[rt].f].son[0]!=rt&&a[a[rt].f].son[1]!=rt;
    	}
    	inline void pushup(int rt){
    		if(!rt)return;
    		a[rt].s=a[a[rt].son[0]].s+a[a[rt].son[1]].s+1;
    		a[rt].v=rt;
    		if(val[a[a[rt].son[0]].v]<val[a[rt].v])a[rt].v=a[a[rt].son[0]].v;
    		if(val[a[a[rt].son[1]].v]<val[a[rt].v])a[rt].v=a[a[rt].son[1]].v;
    	}
    	inline void pushdown(int rt){
    		if(!rt||!a[rt].flag)return;
    		a[a[rt].son[0]].flag^=1;a[a[rt].son[1]].flag^=1;a[rt].flag^=1;
    		swap(a[rt].son[0],a[rt].son[1]);
    	}
    	inline void turn(int rt){
    		int x=a[rt].f,y=a[x].f,k=a[x].son[0]==rt?1:0;
    		if(!isroot(x)){
    			if(a[y].son[0]==x)a[y].son[0]=rt;
    			else a[y].son[1]=rt;
    		}
    		a[rt].f=y;a[x].f=rt;a[a[rt].son[k]].f=x;
    		a[x].son[k^1]=a[rt].son[k];a[rt].son[k]=x;
    		pushup(x);pushup(rt);
    	}
    	void splay(int rt){
    		top=0;
    		stack[++top]=rt;
    		for(int i=rt;!isroot(i);i=a[i].f)stack[++top]=a[i].f;
    		while(top)pushdown(stack[top--]);
    		while(!isroot(rt)){
    			int x=a[rt].f,y=a[x].f;
    			if(!isroot(x)){
    				if((a[y].son[0]==x)^(a[x].son[0]==rt))turn(rt);
    				else turn(x);
    			}
    			turn(rt);
    		}
    	}
    	void access(int rt){
    		for(int i=0;rt;i=rt,rt=a[rt].f){
    			splay(rt);
    			a[rt].son[1]=i;
    			pushup(rt);
    		}
    	}
    	inline void makeroot(int rt){access(rt);splay(rt);a[rt].flag^=1;}
    	int findroot(int rt){
    		access(rt);splay(rt);
    		while(a[rt].son[0])rt=a[rt].son[0];
    		return rt;
    	}
    	inline void split(int x,int y){makeroot(x);access(y);splay(y);}
    	inline void link(int x,int y){makeroot(x);a[x].f=y;}
    	inline void cut(int x,int y){split(x,y);a[x].f=a[y].son[0]=0;}
    	void add_edge(int now,int now_time){
    		int u=edge[now].u,v=edge[now].v;
    		if(u==v&&edge[now].end>now_time){
    			ans++;
    			num[edge[now].end]++;
    			return;
    		}
    		if(findroot(u)!=findroot(v)){link(now+n,u);link(v,now+n);}
    		else{
    			int x;
    			bool flag=false;
    			split(u,v);
    			if(!((a[v].s>>1)&1))flag=true;
    			if(val[a[v].v]>=edge[now].end)x=now;
    			else{
    				x=a[v].v-n;
    				cut(x+n,edge[x].u);cut(x+n,edge[x].v);
    				link(now+n,u);link(v,now+n);
    			}
    			if(flag&&edge[x].end>now_time){
    				ans++;
    				num[edge[x].end]++;
    			}
    		}
    	}
    }
    void work(){
    	int now=1;
    	for(int i=1;i<=q;i++){
    		while(now<=m&&edge[now].start<=i){
    			LCT::add_edge(now,i);
    			now++;
    		}
    		ans-=num[i];
    		if(ans)printf("No
    ");
    		else printf("Yes
    ");
    	}
    }
    void init(){
    	n=read();m=read();q=read();
    	val[0]=MAX;
    	for(int i=1;i<=n;i++){
    		val[i]=MAX;
    		LCT::a[i].s=1;
    		LCT::a[i].v=i;
    	}
    	for(int i=1;i<=m;i++){
    		edge[i].u=read();edge[i].v=read();
    		edge[i].start=read()+1;edge[i].end=read()+1;
    	}
    	sort(edge+1,edge+m+1);
    	for(int i=1;i<=m;i++){
    		val[i+n]=edge[i].end;
    		LCT::a[i+n].s=1;
    		LCT::a[i+n].v=i+n;
    	}
    }
    int main(){
    	init();
    	work();
        return 0;
    }
    
  • 相关阅读:
    wed
    郁闷的星期三
    Mon
    烟斗信息
    10.3
    德国装甲兵之歌
    危急!开发进入瓶颈阶段
    血糯米粥
    上海:烟斗
    如果你的博客被转载?
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9555536.html
Copyright © 2020-2023  润新知