「bzoj 4025: 二分图」

题目

显然二分图没有奇环

于是考虑使用并查集维护一下看看是否存在奇环

我们可以考虑加权并查集,维护出\(x\)\(fa_x\)的实际距离

由于我们只需要考虑奇偶性,于是我们处理出到根的路径异或一下就好了

之后是动态删边的问题,我们可以考虑线段树分治

于是我们需要在线段树分治的时候维护一个并查集,还需要支持撤回操作

我们只需要一个不路径压缩的启发式合并并查集就好了

代码

#include<cstdio>
#include<vector>
#define re register
inline int read() {
    char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
std::vector<int> u[320005],v[320005],f[320005],st[320005];
int n,m,T,now,tp;
int ans[100005],fa[100005],h[100005],dis[100005];
void change(int l,int r,int x,int y,int i,int a,int b) {
    if(x<=l&&y>=r) {u[i].push_back(a),v[i].push_back(b);return;}
    int mid=l+r>>1;
    if(x<=mid) change(l,mid,x,y,i<<1,a,b);
    if(y>=mid+1) change(mid+1,r,x,y,i<<1|1,a,b);
}
inline int find(int x,int opt) {
    if(!opt) now=0;
    while(fa[x]!=x) now^=dis[x],x=fa[x];
    return x;
}
inline int merge(int x,int y) {
    tp=0;
    if(h[x]<h[y]) {dis[x]=(now^1);fa[x]=y;return x;}
    if(h[y]<h[x]) {dis[y]=(now^1);fa[y]=x;return y;}
    h[x]++;fa[y]=x;tp=1;dis[y]=(now^1);return y;
}
inline void clear(int i) {
    for(re int j=st[i].size()-1;~j;--j) {
        int x=st[i][j];
        h[fa[x]]-=f[i][j];fa[x]=x;
    }
}
void solve(int l,int r,int i) {
    for(re int j=0;j<u[i].size();j++) {
        int xx=find(u[i][j],0),yy=find(v[i][j],1);
        if(xx!=yy) st[i].push_back(merge(xx,yy)),f[i].push_back(tp);
        else if(!now) {
            for(re int k=l;k<=r;k++) ans[k]=1;
            clear(i);return;
        }
    }
    if(l==r) {clear(i);return;}
    int mid=l+r>>1;
    solve(mid+1,r,i<<1|1);solve(l,mid,i<<1);
    clear(i);
}
int main() {
    n=read(),m=read(),T=read();
    for(re int i=1;i<=n;i++) fa[i]=i,h[i]=1;
    for(re int x,y,s,t,i=1;i<=m;i++) {
        x=read(),y=read(),s=read()+1,t=read();
        if(s>t) continue;
        change(1,T,s,t,1,x,y);
    }
    solve(1,T,1);
    for(re int i=1;i<=T;i++) puts(ans[i]?"No":"Yes");
    return 0;
}
posted @ 2019-03-13 15:08  asuldb  阅读(103)  评论(0编辑  收藏  举报