zoukankan      html  css  js  c++  java
  • BZOJ 4025: 二分图

    BZOJ 4025: 二分图

    这个题嘛,分治线段树可以做啦…但是我并不想写…毕竟并查集还不能路径压缩只能按质合并…所以,我觉得还是写LCT比较友善…

    LCT维护最晚删除…总体上就是说,从这个树上下来的边,要么消失,要么永远都不会再上来…这样,我们考虑按时间顺序枚举,该加边加边,该删边删边,只是多了如果新边不是树边的话,就和树边比较一下谁更晚删除,之后要么替换,要么滚蛋…之后维护一个num数组表示在第ii分钟的时候,导致不是二分图的边少num[i]个,另外维护现在有多少个这样的边…如果是0就是二分图,反之则不是…

    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstdlib>
    #include <cstring>
    #include <queue>
    #include <iostream>
    using namespace std;
    #define N 400005
    #define ls ch[rt][0]
    #define rs ch[rt][1]
    #define get(rt) (ch[f[rt]][0]!=rt)
    #define isroot(rt) (ch[f[rt]][0]!=rt&&ch[f[rt]][1]!=rt)
    #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++)
    char buf[1000000],*p1,*p2;
    int rd()
    {
        register int x=0;register char c=nc();
        while(c<'0'||c>'9')c=nc();
        while(c>='0'&&c<='9')x=(((x<<2)+x)<<1)+c-'0',c=nc();
        return x;
    }
    struct node{int x,y,l,r;}a[N];
    int ch[N][2],f[N],m,siz[N],mx[N],val[N],num[N],rev[N],n,Q,sum,now;
    void PushUp(int rt){siz[rt]=siz[ls]+siz[rs]+1;mx[rt]=rt;if(val[mx[rt]]>val[mx[ls]])mx[rt]=mx[ls];if(val[mx[rt]]>val[mx[rs]])mx[rt]=mx[rs];}
    void rotate(int rt)
    {
        int x=f[rt],y=f[x],k=get(rt);
        if(!isroot(x))ch[y][ch[y][0]!=x]=rt;
        ch[x][k]=ch[rt][!k];f[ch[x][k]]=x;
        ch[rt][!k]=x;f[x]=rt;f[rt]=y;PushUp(x);PushUp(rt);
    }
    void PushDown(int rt){if(rev[rt])swap(ch[ls][0],ch[ls][1]),swap(ch[rs][0],ch[rs][1]),rev[rt]=0,rev[ls]^=1,rev[rs]^=1;}
    void Update(int rt){if(!isroot(rt))Update(f[rt]);PushDown(rt);}
    void Splay(int rt){for(Update(rt);!isroot(rt);rotate(rt))if(!isroot(f[rt]))rotate(get(f[rt])==get(rt)?f[rt]:rt);}
    void access(int rt){int t=0;while(rt)Splay(rt),rs=t,PushUp(rt),t=rt,rt=f[rt];}
    void makeroot(int rt){access(rt),Splay(rt);swap(ls,rs);rev[rt]^=1;}
    int find(int rt){access(rt),Splay(rt);while(ls)PushDown(rt),rt=ls;Splay(rt);return rt;}
    void link(int rt,int x){makeroot(rt);f[rt]=x;}
    void cut(int rt,int x){makeroot(x);access(rt);Splay(rt);ls=f[x]=0;PushUp(rt);}
    void split(int rt,int x){makeroot(x);access(rt);Splay(rt);}
    bool cmp(const node &a,const node &b){return a.l==b.l?a.r<b.r:a.l<b.l;}
    void add(int p)
    {
        int x=a[p].x,y=a[p].y,tmp,flag=0;
        if(x==y)num[a[p].r]++,sum++;
        else 
        {
            // printf("%d %d
    ",find(x),find(y));
            if(find(x)!=find(y))link(p+n,x),link(y,p+n);
            else
            {
                split(x,y);
                if(!((siz[x]>>1)&1))flag=1;
                if(val[mx[x]]>=a[p].r)tmp=p;
                else tmp=mx[x]-n,cut(tmp+n,a[tmp].x),cut(tmp+n,a[tmp].y),link(p+n,x),link(p+n,y);
                if(flag&&a[tmp].r>now)num[a[tmp].r]++,sum++;
            }
        }
    }
    int main()
    {
        n=rd(),Q=rd();int T=rd();
        for(int i=1;i<=Q;i++)a[i].x=rd(),a[i].y=rd(),a[i].l=rd(),a[i].r=rd();
        sort(a+1,a+Q+1,cmp);
        for(int i=1;i<=n+Q;i++)siz[i]=1,mx[i]=i;
        for(int i=0;i<=n;i++)val[i]=1<<30;
        for(int i=1;i<=Q;i++)val[i+n]=a[i].r;
        for(int i=0,j=1;i<T;i++)
        {
            now=i;
            while(j<=Q&&a[j].l<=i)add(j),j++;
            sum-=num[i];
            if(sum)puts("No");
            else puts("Yes");
        }return 0;
    }
    

      

  • 相关阅读:
    JS 随机整数
    微信小程序 功能函数 支付接口
    JS 正则表达式
    JS 日期 自动补齐 “2017-11-22 14:43”
    schema get_ddl
    StringBuffer 清空
    java中split任意数量的空白字符
    美国法官工资
    纪检委,检察院的工资
    国家司法机构
  • 原文地址:https://www.cnblogs.com/Winniechen/p/9525768.html
Copyright © 2011-2022 走看看