刷题BZOJ 4025 二分图

Posted oyiya

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了刷题BZOJ 4025 二分图相关的知识,希望对你有一定的参考价值。

Description

神犇有一个n个节点的图。因为神犇是神犇,所以在T时间内一些边会出现后消失。神犇要求出每一时间段内这个图是否是二分图。这么简单的问题神犇当然会做了,于是他想考考你。

Input

输入数据的第一行是三个整数n,m,T。

第2行到第m+1行,每行4个整数u,v,start,end。第i+1行的四个整数表示第i条边连接u,v两个点,这条边在start时刻出现,在第end时刻消失。

Output

输出包含T行。在第i行中,如果第i时间段内这个图是二分图,那么输出“Yes”,否则输出“No”,不含引号。

Sample Input

3 3 3
1 2 0 2
2 3 0 3
1 3 1 2

Sample Output

Yes
No
Yes

HINT

样例说明:

0时刻,出现两条边1-2和2-3。

第1时间段内,这个图是二分图,输出Yes。

1时刻,出现一条边1-3。

第2时间段内,这个图不是二分图,输出No。

2时刻,1-2和1-3两条边消失。

第3时间段内,只有一条边2-3,这个图是二分图,输出Yes。

数据范围:

n<=100000,m<=200000,T<=100000,1<=u,v<=n,0<=start<=end<=T。

Solution

这题害了我一天
首先看怎么静态判能不能二分,一条一条边加进去,如果这条边加上会变成一个环,并且这个环还是奇环,那就不能二分;反之,可以
然后看动态的,动态的麻烦就在删除,因为可能把一条树边删掉之后,会有一条非树边代替它变成一条树边,这个做不了;所以就弄一个LCT维护这个树,维护这个图以删除时间为关键字的最大生成树,这样就不会有上述情况发生了
然后按照套路,离线解决
(PS:从早上开始调,一直调到晚上,开始的时候造数据的程序还写错了,会使标程RE,然后有一次其实改对了,但因为数据造错,一直拍不上,结果就和gt拿了一个正确的程序调了半个小时)

#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
const int MAXN=100000+10,MAXM=200000+10,inf=0x3f3f3f3f;
int n,m,tT,V[MAXN+MAXM],sum,f[MAXN+MAXM];
struct edge{
    int u,v;
};
edge side[MAXM];
struct data{
    int opt,val,t,id;
    inline bool operator < (const data &A) const {
        return t<A.t||t==A.t&&opt>A.opt;
    };
};
data p[MAXM<<1];
#define lc(x) ch[(x)][0]
#define rc(x) ch[(x)][1]
struct LCT{
    int ch[MAXN+MAXM][2],fa[MAXN+MAXM],rev[MAXN+MAXM],Mn[MAXN+MAXM],id[MAXN+MAXM],stack[MAXN+MAXM],cnt,val[MAXN+MAXM],size[MAXN+MAXM];
    inline void init()
    {
        memset(Mn,inf,sizeof(Mn));
        memset(val,inf,sizeof(val));
    }
    inline bool nroot(int x)
    {
        return lc(fa[x])==x||rc(fa[x])==x;
    }
    inline void reverse(int x)
    {
        std::swap(lc(x),rc(x));
        rev[x]^=1;
    }
    inline void pushup(int x)
    {
        size[x]=size[lc(x)]+size[rc(x)]+1;
        Mn[x]=val[x],id[x]=x;
        if(Mn[lc(x)]<Mn[x])Mn[x]=Mn[lc(x)],id[x]=id[lc(x)];
        if(Mn[rc(x)]<Mn[x])Mn[x]=Mn[rc(x)],id[x]=id[rc(x)];
    }
    inline void pushdown(int x)
    {
        if(rev[x])
        {
            if(lc(x))reverse(lc(x));
            if(rc(x))reverse(rc(x));
            rev[x]=0;
        }
    }
    inline void rotate(int x)
    {
        int f=fa[x],p=fa[f],c=(rc(f)==x);
        if(nroot(f))ch[p][rc(p)==f]=x;
        fa[ch[f][c]=ch[x][c^1]]=f;
        fa[ch[x][c^1]=f]=x;
        fa[x]=p;
        pushup(f);
        pushup(x);
    }
    inline void splay(int x)
    {
        cnt=0;
        stack[++cnt]=x;
        for(register int i=x;nroot(i);i=fa[i])stack[++cnt]=fa[i];
        while(cnt)pushdown(stack[cnt--]);
        for(register int y=fa[x];nroot(x);rotate(x),y=fa[x])
            if(nroot(y))rotate((lc(y)==x)==(lc(fa[y])==y)?y:x);
        pushup(x);
    }
    inline void access(int x)
    {
        for(register int y=0;x;x=fa[y=x])splay(x),rc(x)=y,pushup(x);
    }
    inline int findroot(int x)
    {
        access(x);splay(x);
        while(lc(x))pushdown(x),x=lc(x);
        splay(x);
        return x;
    }
    inline void makeroot(int x)
    {
        access(x);splay(x);reverse(x);
    }
    inline void split(int x,int y)
    {
        makeroot(x);access(y);splay(y);
    }
    inline void link(int x,int y)
    {
        makeroot(x);fa[x]=y;
    }
    inline void cut(int x,int y)
    {
        split(x,y);fa[x]=lc(y)=0;pushup(y);
    }
};
LCT T;
#undef lc
#undef rc
template<typename T> inline void read(T &x)
{
    T data=0,w=1;
    char ch=0;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')w=-1,ch=getchar();
    while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    x=data*w;
}
template<typename T> inline void write(T x,char c='\0')
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)write(x/10);
    putchar(x%10+'0');
    if(c!='\0')putchar(c);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
inline void add(int now)
{
    int u=side[p[now].id].u,v=side[p[now].id].v,sn=p[now].id+n;
    if(u==v)
    {
        f[sn-n]=1;sum++;
        return ;
    }
    if(T.findroot(u)!=T.findroot(v))T.val[sn]=p[now].val,T.link(sn,u),T.link(sn,v),V[sn-n]=1;
    else
    {
        T.split(u,v);
        int so=T.id[v],nt=T.size[v]>>1;
        if(p[now].val>T.Mn[v])
        {
            if(!(nt&1))sum++,f[so-n]=1;
            T.cut(so,side[so-n].u);
            T.cut(so,side[so-n].v);
            T.val[sn]=p[now].val;
            T.link(sn,u);
            T.link(sn,v);
            V[so-n]=0;V[sn-n]=1;
        }
        else if(!(nt&1))sum++,f[sn-n]=1;
    }
}
inline void del(int now)
{
    int sn=p[now].id+n;
    sum-=f[sn-n];
    if(V[sn-n])
    {
        V[sn-n]=f[sn-n]=0;
        T.cut(sn,side[sn-n].u);T.cut(sn,side[sn-n].v);
    }
    else f[sn-n]=0;
}
int main()
{
    read(n);read(m);read(tT);
    for(register int i=1;i<=m;++i)
    {
        int u,v,st,ed;
        read(u);read(v);read(st);read(ed);
        side[i].u=u;side[i].v=v;
        p[i].t=st;p[i].val=ed;p[i].id=i;p[i].opt=1;
        p[i+m].t=ed;p[i+m].id=i;p[i+m].opt=0;
    }
    std::sort(p+1,p+m*2+1);
    T.init();
    for(register int i=1,j=1;i<=tT;++i)
    {
        for(;p[j].t<i&&j<=m*2;++j)
            if(p[j].opt)add(j);
            else del(j);
        if(sum)puts("No");
        else puts("Yes");
    }
    return 0;
}

以上是关于刷题BZOJ 4025 二分图的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 4025: 二分图

[bzoj4025]二分图_LCT

BZOJ4025 二分图

bzoj4025: 二分图(留坑后填)

BZOJ 4025 二分图(时间树+并查集)

bzoj4025 二分图