bzoj4025 二分图


题意

一个图是二分图当且仅当不存在长度为奇数的环。

先假设边只会出现不会消失:
对于新出现的边\((u,v)\),假如\(u,v\)原来不联通,那么连上也不会出现环,现在考虑\(u,v\)联通:
假如\(u,v\)之间的长度为偶数,那么必定出现奇环,否则直接无视这条边,因为假设之后有一条边能和这条边(长为1,是奇数)构成奇环,那么它必定能和\((u,v)\)这条路径(长为奇数)构成奇环。

于是可以用边带权并查集维护。

对于消失的限制,我们线段树分治,同时不路径压缩,只按秩合并,这样就可以撤销。

code:

#include<bits/stdc++.h>
using namespace std;
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
const int maxn=100010;
const int maxm=200010;
const int maxT=100010;
int n,m,T,top;
int fa[maxn],size[maxn];
bool ans[maxT],d[maxn];
vector<int>seg[maxn<<2];
struct Edge{int u,v,st,ed;}E[maxm];
struct node{int x,y,sizey,dx;}sta[maxm];
inline int read()
{
    char c=getchar();int res=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9')res=res*10+c-'0',c=getchar();
    return res*f;
}
int find(int x){return fa[x]==x?x:find(fa[x]);}
int dis(int x){return fa[x]==x?d[x]:d[x]^dis(fa[x]);}
inline void merge(int u,int v)
{
    int x=find(u),y=find(v);
    if(size[x]>size[y])swap(x,y);
    sta[++top]=(node){x,y,size[y],d[x]};
    d[x]=dis(u)^dis(v)^1;
    fa[x]=y;size[y]+=size[x];
}
inline void cut(int id)
{
    int x=sta[id].x,y=sta[id].y;
    fa[x]=x;d[x]=sta[id].dx;size[y]=sta[id].sizey;
}
void change(int p,int l,int r,int ql,int qr,int id)
{
    if(l>=ql&&r<=qr){seg[p].push_back(id);return;}
    int mid=(l+r)>>1;
    if(ql<=mid)change(ls(p),l,mid,ql,qr,id);
    if(qr>mid)change(rs(p),mid+1,r,ql,qr,id);
}
void solve(int p,int l,int r)
{
    bool flag=1;int now=top;
    for(unsigned int i=0;i<seg[p].size();i++)
    {
        int id=seg[p][i],x,y,u,v;
        u=E[id].u,v=E[id].v;x=find(u),y=find(v);
        if(x!=y)merge(u,v);
        else if(!(dis(u)^dis(v))){flag=0;break;}
    }
    if(flag)
    {
        if(l==r){ans[l]=1;return;}
        int mid=(l+r)>>1;
        solve(ls(p),l,mid);solve(rs(p),mid+1,r);
    }
    while(top>now)cut(top),top--;
}
int main()
{
    n=read(),m=read(),T=read();
    for(int i=1;i<=n;i++)fa[i]=i,d[i]=0,size[i]=1;
    for(int i=1;i<=m;i++)E[i].u=read(),E[i].v=read(),E[i].st=read(),E[i].ed=read();
    for(int i=1;i<=m;i++)change(1,1,T,E[i].st+1,E[i].ed,i);
    solve(1,1,T);
    for(int i=1;i<=T;i++)puts(ans[i]?"Yes":"No");
    return 0;
}
优质内容筛选与推荐>>
1、C# 多线程初级汇总
2、Oracle分析函数之FIRST_VALUE和LAST_VALUE
3、JPA学习笔记(8)——映射一对多关联关系
4、使用Jenkins远程部署war包到tomcat container
5、MySQL闪回工具之myflash 和 binlog2sql


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号