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;
}
原文地址:https://www.cnblogs.com/spfa/p/7363802.html