bzoj4025 二分图

支持加边和删边的二分图判定,分治并查集水之(表示我的LCT还很不熟……仅仅停留在极其简单的模板水平)。

由于是带权并查集,并且不能路径压缩,所以对权值(到父亲距离的奇偶性)的维护要注意一下。

有一个小优化:如果当前图已经不是二分图就不再继续dfs线段树,直接把区间内的每个答案设为No后回溯即可。

这次写了个按size合并,不过随机合并比按size合并还快一点是什么鬼……

按size合并的代码:

/**************************************************************
    Problem: 4025
    User: hzoier
    Language: C++
    Result: Accepted
    Time:13616 ms
    Memory:39288 kb
****************************************************************/
 
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=100010;
void addedge(int,int,int);
void solve(int,int,int);
bool mergeset(int,int,vector<int>&);
void cut(int);
int prt[maxn],size[maxn];
bool d[maxn]={false};
int n,m,e,x,y,s,t;
vector<int>u[maxn<<2],v[maxn<<2];
int main(){
    scanf("%d%d%d",&n,&e,&m);
    for(int i=1;i<=n;i++){
        prt[i]=i;
        size[i]=1;
    }
    while(e--){
        scanf("%d%d%d%d",&x,&y,&s,&t);
        s++;
        addedge(1,m,1);
    }
    solve(1,m,1);
    return 0;
}
void addedge(int l,int r,int rt){
    if(s<=l&&t>=r){
        u[rt].push_back(x);
        v[rt].push_back(y);
        return;
    }
    int mid=(l+r)>>1;
    if(s<=mid)addedge(l,mid,rt<<1);
    if(t>mid)addedge(mid+1,r,rt<<1|1);
}
void solve(int l,int r,int rt){
    vector<int>stk;
    bool ok=true;
    for(int i=0;i<(int)u[rt].size();i++)if(mergeset(u[rt][i],v[rt][i],stk)){
        for(int j=l;j<=r;j++)printf("No
");
        ok=false;
        break;
    }
    if(ok){
        if(l==r)printf("Yes
");
        else{
            int mid=(l+r)>>1;
            solve(l,mid,rt<<1);
            solve(mid+1,r,rt<<1|1);
        }
    }
    if(!stk.empty())for(int i=(int)stk.size()-1;i>=0;i--)cut(stk[i]);
}
bool mergeset(int x,int y,vector<int>&a){
    bool dx=false,dy=false;
    int rx=x,ry=y;
    while(prt[rx]!=rx){
        dx^=d[rx];
        rx=prt[rx];
    }
    while(prt[ry]!=ry){
        dy^=d[ry];
        ry=prt[ry];
    }
    if(rx==ry)return dx==dy;
    if(size[rx]>size[ry])swap(rx,ry);
    prt[rx]=ry;
    size[ry]+=size[rx];
    d[rx]=dx==dy;
    a.push_back(rx);
    return false;
}
void cut(int x){
    int y=prt[x];
    while(prt[y]!=y){
        size[y]-=size[x];
        y=prt[y];
    }
    size[y]-=size[x];
    prt[x]=x;
    d[x]=false;
}
View Code

随机合并的代码(其实两份代码差别并不大):

 1 /**************************************************************
 2     Problem: 4025
 3     User: hzoier
 4     Language: C++
 5     Result: Accepted
 6     Time:13104 ms
 7     Memory:38896 kb
 8 ****************************************************************/
 9  
10 #include<cstdio>
11 #include<cstring>
12 #include<algorithm>
13 #include<vector>
14 using namespace std;
15 inline int randint(){
16     static int a=641,b=61213,c=34179277,x=1894872,p=998244353;
17     x=a*x*x+b*x+c;x%=p;
18     return x<0?(x=-x):x;
19 }
20 const int maxn=100010;
21 void addedge(int,int,int);
22 void solve(int,int,int);
23 bool mergeset(int,int,vector<int>&);
24 int prt[maxn];
25 bool d[maxn]={false};
26 int n,m,e,x,y,s,t;
27 vector<int>u[maxn<<2],v[maxn<<2];
28 int main(){
29     scanf("%d%d%d",&n,&e,&m);
30     for(int i=1;i<=n;i++)prt[i]=i;
31     while(e--){
32         scanf("%d%d%d%d",&x,&y,&s,&t);
33         s++;
34         addedge(1,m,1);
35     }
36     solve(1,m,1);
37     return 0;
38 }
39 void addedge(int l,int r,int rt){
40     if(s<=l&&t>=r){
41         u[rt].push_back(x);
42         v[rt].push_back(y);
43         return;
44     }
45     int mid=(l+r)>>1;
46     if(s<=mid)addedge(l,mid,rt<<1);
47     if(t>mid)addedge(mid+1,r,rt<<1|1);
48 }
49 void solve(int l,int r,int rt){
50     vector<int>stk;
51     bool ok=true;
52     for(int i=0;i<(int)u[rt].size();i++)if(mergeset(u[rt][i],v[rt][i],stk)){
53         for(int j=l;j<=r;j++)printf("No
");
54         ok=false;
55         break;
56     }
57     if(ok){
58         if(l==r)printf("Yes
");
59         else{
60             int mid=(l+r)>>1;
61             solve(l,mid,rt<<1);
62             solve(mid+1,r,rt<<1|1);
63         }
64     }
65     if(!stk.empty())for(int i=(int)stk.size()-1;i>=0;i--){
66         prt[stk[i]]=stk[i];
67         d[i]=false;
68     }
69 }
70 bool mergeset(int x,int y,vector<int>&a){
71     bool dx=false,dy=false;
72     int rx=x,ry=y;
73     while(prt[rx]!=rx){
74         dx^=d[rx];
75         rx=prt[rx];
76     }
77     while(prt[ry]!=ry){
78         dy^=d[ry];
79         ry=prt[ry];
80     }
81     if(rx==ry)return dx==dy;
82     if(randint()&1)swap(rx,ry);
83     prt[rx]=ry;
84     d[rx]=dx==dy;
85     a.push_back(rx);
86     return false;
87 }
View Code

感觉越来越忧伤,却没有办法排解,唉……

原文地址:https://www.cnblogs.com/hzoier/p/6218220.html