zoukankan      html  css  js  c++  java
  • [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)

    题目分析:

    ​ 首先询问是离线的,于是我们可以非常愉快地想到使用线段树分治和可撤销并查集来做此题。

    ​ 并查集判断二分图我们可以把一个点分为两个点(即拓展域并查集),然后交叉合并。如果两个点的祖先相同,则不成立,输出“No”。

    ​ 代码如下(马蜂很丑,不喜勿喷)——

    #include<bits/stdc++.h>
    #define maxn 100005
    using namespace std;
    int n,m,T,top[20],st[20][maxn<<1],ff[20][maxn<<1],sz[20][maxn<<1],f[maxn<<1],s[maxn<<1];vector<int> g1[maxn<<2],g2[maxn<<2];
    inline int gf(int t){return f[t]==t?t:gf(f[t]);}
    inline void modify(int now,int l,int r,int ll,int rr,int s,int t){
    	if(l>=ll&&r<=rr){g1[now].push_back(s),g2[now].push_back(t);return;}int mid=l+r>>1;
    	if(mid>=ll) modify(now<<1,l,mid,ll,rr,s,t);if(mid<rr) modify(now<<1|1,mid+1,r,ll,rr,s,t);
    }
    inline void back(int dep){while(top[dep]) f[st[dep][top[dep]]]=ff[dep][st[dep][top[dep]]],s[st[dep][top[dep]]]=sz[dep][st[dep][top[dep]]],top[dep]--;}
    inline void solve(int dep,int now,int l,int r){
    	int ss=g1[now].size();for(register int i=0;i<ss;i++){
    		int x=g1[now][i],y=g2[now][i],xx=gf(x+n),yy=gf(y+n);x=gf(x),y=gf(y);
    		if(x==y){for(register int j=l;j<=r;j++) puts("No");back(dep);return;}
    		st[dep][++top[dep]]=x,ff[dep][x]=f[x],sz[dep][x]=s[x];st[dep][++top[dep]]=y,ff[dep][y]=f[y],sz[dep][y]=s[y];
    		st[dep][++top[dep]]=xx,ff[dep][xx]=f[xx],sz[dep][xx]=s[xx];st[dep][++top[dep]]=yy,ff[dep][yy]=f[yy],sz[dep][yy]=s[yy];
    		if(s[x]>s[yy]) swap(x,yy);if(s[xx]>s[y]) swap(xx,y);f[x]=yy,f[xx]=y;
    		if(s[x]==s[yy]) s[yy]++;if(s[xx]==s[y]) s[y]++;
    	}
    	if(l==r){puts("Yes");back(dep);return;}int mid=l+r>>1;solve(dep+1,now<<1,l,mid),solve(dep+1,now<<1|1,mid+1,r);back(dep);
    }
    inline int read(){
    	int ret=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-') f=-f;ch=getchar();}
    	while(isdigit(ch)) ret=(ret<<1)+(ret<<3)+ch-'0',ch=getchar();
    	return ret*f;
    }
    int main(){
    	n=read(),m=read(),T=read();for(register int i=1;i<=n*2;i++) f[i]=i,s[i]=1;
    	for(register int i=1,x,y,l,r;i<=m;i++) x=read(),y=read(),l=read()+1,r=read(),modify(1,1,T,l,r,x,y);solve(0,1,1,T);return 0;
    }
    
    
  • 相关阅读:
    华为机试测试- 最小公倍数
    华为机试测试- 字符串最长的数字串
    华为机试测试- 大数相加
    Java 字符串倒序
    java BigDecimal
    华为机试测试-验证尼科彻斯定理
    华为机试测试-矩阵乘法-循环
    JAVA使用脚本引擎执行JS
    javascript学习之位置获取
    javascript学习笔记之DOM
  • 原文地址:https://www.cnblogs.com/jiangxuancheng/p/14186040.html
Copyright © 2011-2022 走看看