bzoj4025 二分图(线段树分治+带权并查集维护路径长奇偶性)

bzoj4025 二分图

原题地址http://www.lydsy.com/JudgeOnline/problem.php?id=4025

题意:
神犇有一个n个节点的图。因为神犇是神犇,所以在T时间内一些边会出现后消失。神犇要求出每一时间段内这个图是否是二分图。

数据范围
n<=100000,m<=200000,T<=100000,1<=u,v<=n,0<=start<=end<=T。

题解:
判断是否是二分图即判断是否没有奇环。

考虑按st顺序一条一条地加边,如果加入一条边,形成偶环,那么对后面的边没有影响,
如果形成奇环,就不是二分图,但是维护一个图显然不好维护,
那么好维护的方式就是转化成树,
形成环时,如果删掉这个环上的某一条边,就还是树,
为了好维护,选择弹掉ed最小的那条边。那么如果成奇环,就是在这个ed最小的边未消失之前都不是二分图。
如果后面的某条边本来会与此条目前被弹掉的边成奇环,而删掉这条边则不能成环或是成偶环,
那么前者不可能发生,因为只有原来那条边会成环才不会加,
后者则原来那条边成奇环,在统计贡献时已经覆盖了此条边在其中会成奇环的时刻。
于是就是维护按ed的最大生成树,用LCT。

但是其实可以按照线段树分治的思想,每条边存在的区间打上标记,在叶子节点输出答案。
思路与上边相似,只是这次成奇环时没有弹边,直接就这个区间的答案都是No即可。

关于这个并查集维护路径奇偶性的正确性证明见这篇相当详细的题解。

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N=100005;
const int M=200005;
int n,m,T,S[2*M],top=0,fa[N],rank[N],c[N];
struct node
{
    int u,v,st,ed;
    node(){}
    node(int u,int v,int st,int ed):u(u),v(v),st(st),ed(ed){}
};
int getfa(int x)
{
    if(fa[x]==x) return x;
    else return getfa(fa[x]);
}
int dis(int x)
{
    if(fa[x]==x||!fa[x]) return 0;
    return c[x]^dis(fa[x]);
}
void merge(int x,int y,int w)
{
    if(rank[x]>rank[y]) swap(x,y);
    if(rank[x]==rank[y]) {S[++top]=-y; rank[y]++;}
    S[++top]=x; fa[x]=y; c[x]=w;
}
void res(int x)
{
    while(top>x)
    {
        if(S[top]<0) rank[-S[top]]--;
        else {fa[S[top]]=S[top]; c[S[top]]=0;}
        top--;
    }
}
void query(int lf,int rg,vector<node> &E)
{
    int pre=top; int mid=(lf+rg)>>1;
    vector<node> L,R; int sz=E.size();
    for(int i=0;i<sz;i++)
    {
        if(E[i].st==lf&&E[i].ed==rg)
        {
            int x=E[i].u; int y=E[i].v;
            int fx=getfa(x); int fy=getfa(y);
            if(fx!=fy)
            {
                int w=dis(x)^dis(y)^1;
                merge(fx,fy,w);
            }
            else
            {
                int w=dis(x)^dis(y);
                if((w&1)==0) {for(int j=lf;j<=rg;j++) printf("No\n"); res(pre); return;}
            }
        }
        else
        {
            if(E[i].ed<=mid) L.push_back(E[i]);
            else if(E[i].st>mid) R.push_back(E[i]);
            else {L.push_back(node(E[i].u,E[i].v,E[i].st,mid));
            R.push_back(node(E[i].u,E[i].v,mid+1,E[i].ed));}
        }
    }
    if(lf==rg){printf("Yes\n"); res(pre); return;}
    query(lf,mid,L); query(mid+1,rg,R);
    res(pre);
}
int main()
{
    scanf("%d%d%d",&n,&m,&T);
    for(int i=1;i<=n;i++) fa[i]=i,rank[i]=0;
    vector<node> e;
    for(int i=1;i<=m;i++)
    {
        int u,v,st,ed; scanf("%d%d%d%d",&u,&v,&st,&ed); st++;
        if(st<=ed) e.push_back(node(u,v,st,ed));
    }
    query(1,T,e);
    return 0;
}
相关文章
相关标签/搜索