zoukankan      html  css  js  c++  java
  • 2015多校第6场 HDU 5354 Bipartite Graph CDQ,并查集

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5354

    题意:求删去每个点后图是否存在奇环(n,m<=1e5)

    解法:很经典的套路,和这题一样:http://www.cnblogs.com/spfa/p/7358672.html CDQ套并查集。 这题最开始是看了南神的代码才懂的,http://blog.csdn.net/hdu2014/article/details/47450709    因为要判断每一个点,而且一旦一个点之外的几个点形成了奇环的话这个点一定就是No,所以用分治来解。先判断每一段之外的点是否会成为奇环,如果是的话,这一段就全是No,反之就把这些点放到并查集里并记录,然后分治当前段,直到分治进行到单个点,分治结束后把并查集还原。真是神奇的分治。orz

    //HDU 5354
    #include <bits/stdc++.h>
    using namespace std;
    typedef pair<int,int>pi;
    const int maxn = 400020;
    vector<pi>E[maxn*2];
    int n,m,f[maxn],sz[maxn],val[maxn],ans[maxn];
    bool in(int a, int L, int R){
        return a>=L&&a<=R;
    }
    void solve(int l, int r, int x, vector<pi>&tp);
    pi find_set(int x){
        int ret=x;
        int w=0;
        for(;f[ret]!=ret;ret=f[ret]) w^=val[ret];
        w^=val[ret];
        return pi(ret,w);
    }
    void CDQ(int l, int r, int x){
        if(l == r){
            ans[l]=1;
            return;
        }
        E[x<<1].clear();
        E[x<<1|1].clear();
        vector<pi>tp[2];
        int mid = (l+r)>>1;
        for(int i=0; i<E[x].size(); i++){
            int a=E[x][i].first,b=E[x][i].second;
            if(in(a,l,mid)||in(b,l,mid)) E[x<<1].push_back(E[x][i]);
            else tp[0].push_back(E[x][i]);
            if(in(a,mid+1,r)||in(b,mid+1,r)) E[x<<1|1].push_back(E[x][i]);
            else tp[1].push_back(E[x][i]);
        }
        solve(l,mid,x<<1,tp[0]);
        solve(mid+1,r,x<<1|1,tp[1]);
    }
    void solve(int l, int r, int x, vector<pi>&tp)
    {
        vector<pi>res;
        bool flag=0;
        for(int i=0; i<tp.size(); i++){
            int u=tp[i].first,v=tp[i].second;
            pi fu = find_set(u), fv = find_set(v);
            if(fu.first==fv.first){
                if(!(fu.second^fv.second)){
                    flag = 1;
                    break;
                }
            }
            else{
                int t1=sz[fu.first]>sz[fv.first]?fu.first:fv.first;
                int t2=fu.first+fv.first-t1;
                int t3=fu.second^fv.second;
                f[t2]=t1;
                sz[t1]+=sz[t2];
                res.push_back(pi(t2,t3));
                val[t2]^=t3;
            }
        }
        if(flag){
            for(int i=l; i<=r; i++) ans[i]=0;
        }
        else CDQ(l,r,x);
        for(int i=res.size()-1; i>=0; i--){
            int u=res[i].first;
            sz[f[u]]-=sz[u];
            val[u]^=res[i].second;
            f[u]=u;
        }
    }
    int main()
    {
        int T;
        scanf("%d", &T);
        while(T--)
        {
            E[1].clear();
            scanf("%d%d",&n,&m);
            for(int i=1; i<=n; i++) f[i]=i,sz[i]=1,val[i]=1;
            for(int i=1; i<=m; i++){
                int u,v;
                scanf("%d%d",&u,&v);
                if(u>v) swap(u,v);
                E[1].push_back(pi(u,v));
            }
            CDQ(1,n,1);
            for(int i=1; i<=n; i++) printf("%d",ans[i]);
            printf("
    ");
        }
        return 0;
    }
    
  • 相关阅读:
    Code review
    一点心得
    有关双向追踪性的一点感觉
    测试用例分析的一点心得
    js简单的抽屉菜单
    新的感受
    linux的VPS如何分区
    PHP中Unicode转码和解码的实现
    xampp安装及配置
    js Unicode编码转换
  • 原文地址:https://www.cnblogs.com/spfa/p/7363802.html
Copyright © 2011-2022 走看看