zoukankan      html  css  js  c++  java
  • BZOJ 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。
     
    题解:
      这个题目,我们考虑套路CDQ 图分治,以边出现的时间L,R分治,每次我们算区间(L~R)十分可能。
      对于时间段L~R,我们先把时间等于L~R的边加入图中,如果出现了基环,那么这一段时间都是不可能的,否则,我们将剩下的边按照<mid,>mid和在中间分类,把在中间的边拆成两个进行下一次递归,如果递归到最后一层都没有问题就是好的。
      然后,我们用并查集维护这个图的联通性,带一个权,维护这个点到到父亲的边数的基偶性,这样就可以维护出图中十分存在基环,具体,如果在一个并查集中,那么环的基偶性就是get(x)^get(y)^1,get(x)是x到首元素的基偶性,因为异或就相当于加,所以画一个图就理解了。对于合并,就直接讲首按照dep合并,这样是logn的,如果fa[fx]=fy,就改一下fx的权,改get(x)^get(y)^1,get(x),这个是等效的,证明的话自己思考一下,还是比较有趣的。
     
    代码:
    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #include <iostream>
    #include <vector>
    #define MAXN 201000
    using namespace std;
    int fa[MAXN],rak[MAXN],d[MAXN];
    int s1[MAXN*2],s2[MAXN],ans[MAXN],top=0;
    struct edge{
        int x,y,s,e;
    };
    vector<edge> S;
    int n,m,t;
    
    int find(int x){
        while(x!=fa[x]) x=fa[x];
        return x;
    }
    
    int getdis(int x){
        int ans=0;
        while(x!=fa[x]) ans^=d[x],x=fa[x];
        return ans;
    }
    
    void mearge(int x,int y,int c){
        if(rak[x]>rak[y]){
            s1[++top]=y;s2[top]=1;
            fa[y]=x,d[y]=c;
        }
        else if(rak[y]>rak[x]){
            s1[++top]=x;s2[top]=1;
            fa[x]=y;d[x]=c;
        }
        else{
            rak[x]++;fa[y]=x;
            s1[++top]=y;s2[++top]=0;
            fa[y]=x,d[y]=c;
        }
    }
    
    void fenzhi(int l,int r,vector<edge> hh){
        int now=top,mid=(l+r)/2;
        vector<edge> ll,rr;
        for(int i=0,len=hh.size();i<len;i++){
            edge a=hh[i];
            int x=a.x,y=a.y;
            if(a.s==l&&a.e==r){
                int fx=find(x),fy=find(y),c=getdis(x)^getdis(y)^1;
                if(fx!=fy) mearge(fx,fy,c);
                else if(c&1){
                    for(int i=l;i<=r;i++) ans[i]=0;
                    while(now!=top){
                        if(s2[top]==0) rak[fa[s1[top]]]--;//
                        fa[s1[top]]=s1[top];d[s1[top]]=0;top--;
                    }
                    return;
                }
            }
            else if(a.e<=mid) ll.push_back(a);
            else if(a.s>mid) rr.push_back(a);
            else{
                edge b=a;
                b.e=mid;ll.push_back(b);
                b=a;b.s=mid+1;
                rr.push_back(b);
            }
        }
        if(l==r) ans[l]=1;
        else fenzhi(l,mid,ll),fenzhi(mid+1,r,rr);
        while(now!=top){
            if(s2[top]==0) rak[fa[s1[top]]]--;//
            fa[s1[top]]=s1[top];d[s1[top]]=0;top--;
        }
    }
    
    int main()
    {
        scanf("%d%d%d",&n,&m,&t);
        for(int i=1;i<=m;i++){
            int x,y,s,t;scanf("%d%d%d%d",&x,&y,&s,&t);s++;
            if(s<=t) S.push_back((edge){x,y,s,t});
        }
        for(int i=1;i<=n;i++) fa[i]=i,rak[i]=0,d[i]=0;
        for(int i=1;i<=n;i++) ans[i]=1;
        fenzhi(1,t,S);
        for(int i=1;i<=t;i++){
            if(ans[i]) printf("Yes
    ");
            else printf("No
    ");
        }
        return 0;
    }
  • 相关阅读:
    Android Studio --“Cannot resolve symbol” 解决办法
    js与android webview交互
    关于post与get请求参数存在特殊字符问题
    Fragment 学习笔记(1)
    Android Studio 错误集
    UVA
    UVA
    UVALive
    考试题string——线段树。
    洛谷 1552 [APIO2012]派遣
  • 原文地址:https://www.cnblogs.com/renjianshige/p/7618107.html
Copyright © 2011-2022 走看看