zoukankan      html  css  js  c++  java
  • bzoj4025 二分图

    题目链接:bzoj4025

    题目大意:

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


    题解:

    cdq+并查集判奇环

    二分图,不存在奇环的图就叫二分图。所以用带权并查集来判断奇环。为了(?),按秩合并且不用路径压缩(方便还原并查集)。按秩合并的话就是有个rank[i]值表示该集的高度,每次合并就把rank小的合到大的那里,使复杂度最小。

    那么判断的时候对于一边上的两点,若不在一个并查集那么肯定不会构成环,若在的话,就getdistance判断是否是奇环。

    分治过程:
    1、处理完全符合分治区间时间段的所有边合并并判埋是否有奇环。若有的话,该时间段的都不是二分图了,就可以退了...
    2、其余不完全符合区间的都在左边就弄到左边,都在右边就弄到右边。若跨区间,则把左半部分弄到左边,右半部分到右边
    3、若分治到底,就说明这个时间段是二分图
    4、没有到底就分治左边,分治右边啊
    5、把并查集恢复至初始的样子

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<vector>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define maxn 201000
    
    struct node {int x,y,s,t;};
    vector<node> S;
    int tp,sta1[maxn];bool sta2[maxn];
    int rk[maxn],fa[maxn],d[maxn],ans[maxn];
    int ffind(int x)
    {
    	while (x!=fa[x]) x=fa[x];
    	return x;
    }
    void merge(int fx,int fy,int c)
    {
    	if (rk[fx]>rk[fy]) 
    	{
    		sta1[++tp]=fy;sta2[tp]=1;
    		fa[fy]=fx,d[fy]=c;
    	}
    	else if (rk[fx]<rk[fy]) 
    	{
    		sta1[++tp]=fx;sta2[tp]=1;
    		fa[fx]=fy,d[fx]=c;
    	}
    	else
    	{
    		rk[fx]++;
    		sta1[++tp]=fy;sta2[tp]=0;
    		fa[fy]=fx;
    		d[fy]=c;
    	}
    }
    int getd(int x)
    {
    	int ans=0;
    	while (x!=fa[x]) ans^=d[x],x=fa[x];
    	return ans;
    }
    void solve(int l,int r,vector<node> M)//int ll,int rr
    {
    	int i,mid=(l+r)>>1,now=tp;
    	vector<node> ll,rr;
    	for (i=0;i<M.size();i++)
    	{
    		node a=M[i];
    		if (a.s==l && a.t==r)
    		{
    			 int x=a.x,y=a.y;
    			 int fx=ffind(x),fy=ffind(y);
    			 int c=getd(x)^getd(y)^1;
    			 if (fx!=fy) merge(fx,fy,c);
    			 else if (c&1)
    			 {
    				 for (int j=l;j<=r;j++) ans[j]=0;
    				 while (now!=tp) 
    				 {
    					 if (!sta2[tp]) rk[sta1[tp]]--;
    					 fa[sta1[tp]]=sta1[tp];d[sta1[tp]]=0;tp--;
    				 }
    				 return;
    			 }
    		}
    		else if (a.t<=mid) ll.push_back(a);
    		else if (a.s>mid) rr.push_back(a);
    		else
    		{
    			node b=a;b.t=mid;
    			ll.push_back(b);
    			b=a;b.s=mid+1;
    			rr.push_back(b);
    		}
    	}
    	if (l==r) ans[l]=1;
    	else solve(l,mid,ll),solve(mid+1,r,rr);
    	while (now!=tp) 
    	{
    		if (!sta2[tp]) rk[sta1[tp]]--;
    		fa[sta1[tp]]=sta1[tp];d[sta1[tp]]=0;tp--;
    	}
    }
    int main()
    {
    	freopen("a.in","r",stdin);
    	freopen("a.out","w",stdout);
    	int n,m,T,i;tp=0;
    	scanf("%d%d%d",&n,&m,&T);//T段时间
    	for (i=1;i<=n;i++) d[i]=0,fa[i]=i;
    	for (i=1;i<=m;i++)
    	{
    		node t;
    		scanf("%d%d%d%d",&t.x,&t.y,&t.s,&t.t);
    		t.s++;if (t.s<=t.t) S.push_back(t);
    		//s时刻出现t时刻消失即于第s+1时段~第t时段存在
    	}	
    	for (i=1;i<=T;i++) ans[i]=1;
    	solve(1,T,S);
    	for (i=1;i<=T;i++) if (ans[i]) printf("Yes
    ");else printf("No
    ");
    	return 0;
    }


  • 相关阅读:
    hdu 2065
    hdu 1999
    hdu 1562
    hdu 1728
    hdu 1180
    hdu 1088
    hdu 2133
    很好的例子。。
    putty 多标签式浏览
    df
  • 原文地址:https://www.cnblogs.com/Euryale-Rose/p/6527807.html
Copyright © 2011-2022 走看看