BZOJ4025 二分图(线段树分治+可撤销带权并查集)

根据数据是区间,也是时间,应该可以想到时间线段树分治

问题就是如何查询二分图。

一般判定二分图就是判断是否存在奇数环。

那么奇数环就是当我们加入一条边,如果他们本身是联通的并且距离为偶数,这样就是奇数,并且一旦找到奇数环,下面的时间永远是奇数环

因此我们可以用带权并查集来维护距离信息,这是经典套路,本体距离只有奇偶,因此直接异或判断。

但是我们回溯的时候需要撤销并查集,因此不能路径压缩,只能采用按秩合并的思路,并且记录栈,按插入的顺序再撤销他

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
const int N=2e5+10;
struct node{
    int l,r;
    vector<pll> num;
}tr[N<<2];
struct seg{
    int x,y,f,mx,d;
};
int n,m,T;
int p[N],sz[N],d[N];
stack<seg> s;
int ans[N];
int find(int x){
    if(p[x]!=x){
        return find(p[x]);
    }
    return x;
}
void build(int u,int l,int r){
    if(l==r){
        tr[u]={l,r};
    }
    else{
        tr[u]={l,r};
        int mid=l+r>>1;
        build(u<<1,l,mid);
        build(u<<1|1,mid+1,r);
    }
}
void modify(int u,int l,int r,pll x){
    if(tr[u].l>=l&&tr[u].r<=r){
        tr[u].num.push_back(x);
        return ;
    }
    int mid=tr[u].l+tr[u].r>>1;
    if(l<=mid)
        modify(u<<1,l,r,x);
    if(r>mid)
        modify(u<<1|1,l,r,x);
}
void init(){
    int i;
    for(i=1;i<=n;i++){
        p[i]=i,d[i]=0,sz[i]=1;
    }
}
int getdis(int x){
    if(x!=p[x]){
        return (d[x]^getdis(p[x]));
    }
    return d[x];
}
void solve(int u){
    int i;
    int flag=0;
    int cnt=0;
    for(i=0;i<(int)tr[u].num.size();i++){
        int x=tr[u].num[i].first,y=tr[u].num[i].second;
        int pa=find(x),pb=find(y);
        if(pa==pb){
            int a=getdis(x);
            int b=getdis(y);
            if(a==b){
                flag=1;
                break;
            }
        }
        else{
            if(sz[pa]>sz[pb]){
                swap(x,y);
                swap(pa,pb);
            }
            int tmp=p[pa];
            p[pa]=pb;
            d[pa]=d[x]^d[y]^1;
            s.push({pa,pb,tmp,sz[pb],0});
            sz[pb]+=sz[pa];
            cnt++;
        }
    }
    if(!flag){
        if(tr[u].l==tr[u].r){
            ans[tr[u].l]=1;
        }
        else{
            int mid=tr[u].l+tr[u].r>>1;
            solve(u<<1);
            solve(u<<1|1);
        }
    }
    while(cnt--){
        auto tmp=s.top();
        s.pop();
        p[tmp.x]=tmp.f;
        sz[tmp.y]=tmp.mx;
        d[tmp.x]=tmp.d;
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin>>n>>m>>T;
    int i;
    build(1,1,T);
    for(i=1;i<=m;i++){
        int a,b,c,d;
        cin>>a>>b>>c>>d;
        modify(1,c+1,d,{a,b});
    }
    init();
    solve(1);
    for(i=1;i<=T;i++){
        if(ans[i]){
            cout<<"Yes"<<endl;
        }
        else{
            cout<<"No"<<endl;
        }
    }
    return 0;
}
View Code

 

posted @ 2020-12-12 14:39  朝暮不思  阅读(93)  评论(0编辑  收藏  举报