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

    这题想不出来。

    不浪费时间了。

    以后找时间填。

     --------------------update---------------

    就是判奇环咯

    然而LCT我搞不出来。。

    是因为对于当前的最大生成树,新时间加入的边可能是比前面最大生成树里最小边要大,然后就要找到最大生成树里最小的边。。这样要化边为点我萎了还是写不出来你们去%吧

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<map>
    using namespace std;
    
    struct node
    {
        int x,y;
    }a[210000];
     
    struct heap_st
    {
        int st,ed,id;
        friend bool operator>(heap_st n1,heap_st n2){return n1.st>n2.st;}
    };priority_queue<heap_st,vector<heap_st>,greater<heap_st> >A;
    struct heap_ed
    {
        int ed,id;
        friend bool operator>(heap_ed n1,heap_ed n2){return n1.ed>n2.ed;}
    };priority_queue<heap_ed,vector<heap_ed>,greater<heap_ed> >B;
    struct heap_mt
    {
        int ed,id;
        friend bool operator>(heap_mt n1,heap_mt n2){return n1.ed<n2.ed;}
    };priority_queue<heap_mt,vector<heap_mt>,greater<heap_mt> >C;
     
     
    //---------edge&&heap---------------
     
    
    struct LCT
    {
        int f,c,son[2];
        bool fz;
    }tr[210000];
    void yu(int n){for(int i=1;i<=n;i++)tr[i].c=1,tr[i].fz=false;}
    void update(int x)
    {
        int lc=tr[x].son[0],rc=tr[x].son[1];
        tr[x].c=tr[lc].c+tr[rc].c+1;
    }
    void reverse(int x)
    {
        tr[x].fz=false;
        swap(tr[x].son[0],tr[x].son[1]);
        int lc=tr[x].son[0],rc=tr[x].son[1];
        tr[lc].fz=1-tr[lc].fz;
        tr[rc].fz=1-tr[rc].fz;
    }
    void rotate(int x,int w)
    {
        int f=tr[x].f,ff=tr[f].f;
        int R,r;
        
        R=f;r=tr[x].son[w];
        tr[R].son[1-w]=r;
        if(r!=0)tr[r].f=R;
        
        R=ff;r=x;
              if(tr[R].son[0]==f)tr[R].son[0]=r;
        else if(tr[R].son[1]==f)tr[R].son[1]=r;
        tr[r].f=R;
        
        R=x;r=f;
        tr[R].son[w]=r;
        tr[r].f=R;
        
        update(f);
        update(x);
    }
    bool isroot(int x)
    {
        if(tr[x].f!=0&&(tr[tr[x].f].son[0]==x||tr[tr[x].f].son[1]==x))return false;
        return true;
    }
    int tmp[210000];
    void splay(int x,int rt)
    {
        int s=0,i=x;
        while(isroot(i)==false)
        {
            tmp[++s]=i;
            i=tr[i].f;
        } 
        tmp[++s]=i;
        while(s!=0)
        {
            i=tmp[s];s--;
            if(tr[i].fz==true)reverse(i);
        }
        
        while(isroot(x)==false)
        {
            int f=tr[x].f,ff=tr[f].f;
            if(isroot(f)==true)
            {
                if(x==tr[f].son[0])rotate(x,1);
                else rotate(x,0);
            }
            else
            {
                     if(tr[f].son[0]==x&&tr[ff].son[0]==f){rotate(f,1);rotate(x,1);}
                else if(tr[f].son[1]==x&&tr[ff].son[0]==f){rotate(x,0);rotate(x,1);}
                else if(tr[f].son[0]==x&&tr[ff].son[1]==f){rotate(x,1);rotate(x,0);}
                else if(tr[f].son[1]==x&&tr[ff].son[1]==f){rotate(f,0);rotate(x,0);}
            }
        }
    }
    
    //splay
     
    void access(int x) 
    {
        int y=0;
        while(x!=0)
        {
            splay(x,0);
            tr[x].son[1]=y;
            if(y!=0)tr[y].f=x;
            update(x);
            y=x;x=tr[x].f;
        }
    }
    void makeroot(int x)
    {
        access(x);splay(x,0);
        tr[x].fz=1-tr[x].fz;
    }
    void Link(int x,int y)
    {
        makeroot(x);tr[x].f=y;access(x);
    }
    void Cut(int x,int y)
    {
        makeroot(x);
        access(y);splay(y,0);
        tr[tr[y].son[0]].f=0;tr[y].son[0]=0;
        update(y);
    }
    int findroot(int x)
    {
        access(x);splay(x,0);
        while(tr[x].son[0]!=0)x=tr[x].son[0];
        return x;
    }
     
    //simple
     
    int getdis(int x,int y)
    {
        makeroot(x);
        access(y);splay(y,0);
        int ret=1;
        while(y!=x){y=tr[y].son[0];ret+=tr[tr[y].son[1]].c+1;}
        return ret;
    }
     
     
    //-------------------LCT------------------- 
     
     
    bool intree[210000];//该边是否在树上 
    int main()
    {
        freopen("data.in","r",stdin);
        freopen("data.out","w",stdout);
        
        int n,m,T;
        scanf("%d%d%d",&n,&m,&T);yu(n);
        int st,ed;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&a[i].x,&a[i].y);
            scanf("%d%d",&st,&ed);st++;ed++;
            if(st>=ed){i--;m--;continue;}
            heap_st tt;
            tt.st=st, tt.ed=ed, tt.id=i;
            A.push(tt);
        }
         
        int tim=0;
        memset(intree,false,sizeof(intree));
        for(int t=1;t<=T;t++)
        {
            while(B.empty()==false)
            {
                heap_ed h=B.top();
                if(h.ed==t)
                {
                    B.pop();
                    int k=h.id;
                    if(intree[k]==true)
                    {
                        intree[k]=false;
                        Cut(a[k].x,a[k].y);
                    }
                }
                else break;
            }
             
            //----------结束时间到,删除树上边,非树上边可以直接无视,更新-------
             
            while(A.empty()==false)
            {
                heap_st h=A.top();
                if(h.st==t)
                {
                    A.pop();
                     
                    heap_ed tt;
                    tt.ed=h.ed, tt.id=h.id;
                    B.push(tt);
                     
                    heap_mt uu;
                    uu.ed=h.ed, uu.id=h.id;
                    C.push(uu);
                }
                else break;
            }
             
            //----------起始时间到,将边入堆---------- 
             
            while(C.empty()==false)
            {
                heap_mt h=C.top();C.pop();
                if(h.ed<=t)break;
                int k=h.id;
                int x=a[k].x,y=a[k].y;
                if(x==y){tim=max(tim,h.ed-1);continue;}
                if(findroot(x)!=findroot(y))
                {
                    intree[k]=true;
                    Link(x,y);
                }
                else
                {
                    if(getdis(x,y)%2==1)
                        tim=max(tim,h.ed-1);
                }
            }
     
            //----------将树边连满&&判奇环---------------- 
             
            if(t<=tim)printf("No
    ");
            else printf("Yes
    ");
        }
        return 0;
    }
    lj的WAcode

    --------------------然而cdq+带权并查集搞出来了。。。-----------------------

    感觉这个不算cdq分治,只是普通分治而已-_-! upd:这个东西其实叫线段树分治。。。。。

    具体怎么做呢,就是类似线段树一样把每一时间段下放影响,这样可以保证对于当前这一段包含的边都是没消失的,然后假如遇到奇环就把当前区间全部设为false就行。

    dis可以直接用异或代替,因为只是要判奇偶性,路径不用压缩,修改需要父亲,分治可以保证平衡。

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    using namespace std;
    
    int fa[210000],d[210000];
    int findfa(int x)
    {
        while(x!=fa[x])x=fa[x];
        return x;
    }
    int getdis(int x)
    {
        int dis=0;
        while(x!=fa[x])dis^=d[x],x=fa[x];
        return dis;
    }
    
    //---------union-find sets------------- 
    
    int top,sta[410000];bool v[410000];
    int rak[210000];
    void Link(int x,int y,int dis)
    {
        if(rak[x]>rak[y])
        {
            top++;
            sta[top]=y,v[top]=true;
            fa[y]=x,d[y]=dis;
        }
        else if(rak[x]<rak[y])
        {
            top++;
            sta[top]=x,v[top]=true;
            fa[x]=y,d[x]=dis;
        }
        else
        {
            rak[x]++;top++;
            sta[top]=y,v[top]=false;
            fa[y]=x,d[y]=dis;
        }
    }
    void Cut(int now)
    {
        while(now!=top)
        {
            int k=sta[top];top--;
            if(v[top+1]==false)rak[fa[k]]--;
            fa[k]=k, d[k]=0;
        }
    }
    
    //------------------玄学-------------------------------- 
    
    struct edge{int x,y,st,ed;};
    bool as[210000];
    void cdq(int l,int r,vector<edge> hh)
    {
        int mid=(l+r)/2;
        vector<edge> ll,rr;
        
        int len=hh.size(),now=top;
        for(int i=0;i<len;i++)
        {
            edge e=hh[i];
            if(e.st==l&&e.ed==r)
            {
                int x=e.x,y=e.y;
                int fx=findfa(x),fy=findfa(y);
                int dis=getdis(x)^getdis(y)^1;
                
                if(fx!=fy)Link(fx,fy,dis);
                else if((dis&1)>0)
                {
                    for(int i=l;i<=r;i++)as[i]=false;
                    Cut(now);
                    return ;
                }
            }
            else if(e.ed<=mid)  ll.push_back(e);
            else if(mid+1<=e.st)rr.push_back(e);
            else
            {
                edge lc,rc;lc=rc=e;
                lc.ed=mid;rc.st=mid+1;
                ll.push_back(lc);
                rr.push_back(rc);
            }
        }
        
        if(l==r)as[l]=true;
        else cdq(l,mid,ll), cdq(mid+1,r,rr);
        Cut(now);
    }
    
    vector<edge> S;
    int main()
    {
     
        int n,m,T;
        scanf("%d%d%d",&n,&m,&T);
        for(int i=1;i<=m;i++)
        {
            int x,y,st,ed;
            scanf("%d%d%d%d",&x,&y,&st,&ed);
            if(st>=ed)continue;
            st++; S.push_back((edge){x,y,st,ed});
        }
        
        for(int i=1;i<=n;i++)fa[i]=i;
        memset(d,0,sizeof(d));
        memset(rak,0,sizeof(rak));
        top=0;
        
        cdq(1,T,S);
        
        for(int i=1;i<=T;i++)
            if(as[i]==true)printf("Yes
    ");
            else printf("No
    ");
        return 0;
    }
    现在已经看不懂的代码

    -------------------------------再一次upd----------------------------------------

    学会了线段树分治就是傻子题了,只要上并查集判奇环即可

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    using namespace std;
    
    struct edge{int x,y;}e[210000];
    struct node
    {
        int l,r,lc,rc;
        vector<int>id,u;
    }tr[210000];int trlen;
    void bt(int l,int r)
    {
        int now=++trlen;
        tr[now].l=l;tr[now].r=r;
        tr[now].lc=tr[now].rc=-1;
        if(l<r)
        {
            int mid=(l+r)/2;
            tr[now].lc=trlen+1;bt(l,mid);
            tr[now].rc=trlen+1;bt(mid+1,r);
        }
    }
    void insert(int now,int l,int r,int p)
    {
        if(tr[now].l==l&&tr[now].r==r)
        {
            tr[now].id.push_back(p);
            return ;
        }
        int lc=tr[now].lc,rc=tr[now].rc;
        int mid=(tr[now].l+tr[now].r)/2;
        
             if(r<=mid)  insert(lc,l,r,p);
        else if(mid+1<=l)insert(rc,l,r,p);
        else insert(lc,l,mid,p),insert(rc,mid+1,r,p);
    }
    
    //---------------------------------------init----------------------------------------------------
    
    int fa[210000]; const int ot=101000;
    int findfa(int x)
    {
        if(fa[x]<0)return x;
        return findfa(fa[x]);
    }
    void merge(int now,bool &bk,int x,int y)
    {
        int fx1=findfa(x),fy2=findfa(y+ot);
        if(fx1!=fy2)
        {
            if(fa[fx1]>fa[fy2])
            {
                tr[now].u.push_back(fx1);
                fa[fy2]+=fa[fx1];
                fa[fx1]=fy2;
            }
            else
            {
                tr[now].u.push_back(fy2);
                fa[fx1]+=fa[fy2];
                fa[fy2]=fx1;
            }
        }
        int fy1=findfa(y),fx2=findfa(x+ot);
        if(fx2!=fy1)
        {
            if(fa[fx2]>fa[fy1])
            {
                tr[now].u.push_back(fx2);
                fa[fy1]+=fa[fx2];
                fa[fx2]=fy1;
            }
            else
            {
                tr[now].u.push_back(fy1);
                fa[fx2]+=fa[fy1];
                fa[fy1]=fx2;
            }
        }
        
        if(findfa(fx1)==findfa(fx2)||findfa(fy1)==findfa(fy2))bk=false;
    }
    struct Answer{int l,r;bool b;}as[110000];int tp;
    void dfs(int now)
    {
        bool bk=true;
        for(int i=0;i<tr[now].id.size();i++)
            merge(now,bk,e[tr[now].id[i]].x,e[tr[now].id[i]].y);
        if(bk==false)
        {
            as[++tp].l=tr[now].l,as[tp].r=tr[now].r,as[tp].b=false;    
        }
        else
        {
            if(tr[now].l==tr[now].r)as[++tp].l=as[tp].r=tr[now].l,as[tp].b=true;
            else
            {
                dfs(tr[now].lc);
                dfs(tr[now].rc);
            }
        }
        
        for(int i=0;i<tr[now].u.size();i++)
            fa[tr[now].u[i]]=-1;
    }
    
    int main()
    {
        freopen("a.in","r",stdin);
        freopen("a.out","w",stdout);
        int n,m,T,st,ed;
        scanf("%d%d%d",&n,&m,&T);
        trlen=0;bt(1,T);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d%d",&e[i].x,&e[i].y,&st,&ed);
            if(st>=ed){i--,m--;continue;}
            insert(1,st+1,ed,i);
        }
        memset(fa,-1,sizeof(fa));
        tp=0;dfs(1);
        for(int i=1;i<=tp;i++)
            for(int j=as[i].l;j<=as[i].r;j++)
                if(as[i].b)printf("Yes
    ");
                else printf("No
    ");
        
        return 0;
    }
  • 相关阅读:
    html 带渐变的吸顶效果 vue
    Linux添加环境变量
    C#集合通论
    Android adb 命令导出数据库
    查看签名方式及签名信息
    啥 啥 啥,服务治理是个啥
    令牌桶、漏斗、冷启动限流在sentinel的应用
    MySQL事务
    MySQL优化
    MySQL视图、存储过程、函数、触发器
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/8516221.html
Copyright © 2011-2022 走看看