zoukankan      html  css  js  c++  java
  • BZOJ 4025 二分图 LCT维护最大生成树

    挺好的一道题.
    假设连了 $i$ 条边且恰好连成了一棵树.
    那么下一条连边有 3 种情况:
    1.连接两个不连通的点.
    2.连接的两个点联通,且能构成奇环.
    3.连接的两个点联通,能构成偶环.
    对于情况1,直接将两个点相连即可.
    对于情况2,显然这个奇环存在的时间为 $[s_{i+1},min_{E subseteq cycle}^{} { t _{E}}]$
    即加入该边的时间到环上消失时间最短的边的时间.
    由于我们判断二分图时只需判断是否存在奇环,奇环具体有几个是不要紧的.
    那么如果环上的边会和后面的边形成奇环的话环上的边的消失时间一定不可以等于 $min_{E subseteq cycle}^{} { t _{E}}$
    因为如果等于这个最小值的话还是无意义的(边 $i+1$ 已经贡献了)
    所以这就意味着要删掉环上消失时间最小的那条边,这个可以用 LCT 来维护最大生成树.
    对于情况3,加入一条边是构不成奇环的,然后我们发现由于环的大小是偶数,所以即使删掉两个点环的奇偶性是不变的.
    考虑到情况 2 中我们希望环上消失时间最小值尽量大,所以和情况 2 一样替换掉消失时间最小的边即可.

    #include <cstdio> 
    #include <vector>   
    #include <algorithm>
    #define N 800004    
    #define inf 1000000000 
    #define setIO(s) freopen(s".in","r",stdin)  ,freopen(s".out","w",stdout)     
    using namespace std;     
    int n,m,T,cnt;    
    struct Edge 
    { 
        int u,v,s,t;   
        Edge(int u=0,int v=0,int s=0,int t=0):u(u),v(v),s(s),t(t){}   
    }e[N];                           
    struct Link_Cut_Tree 
    {
        #define lson p[x].ch[0] 
        #define rson p[x].ch[1]                   
        int sta[N];   
        struct Node 
        {
            int min,id,val,size,rev,f,ch[2];                 
        }p[N];       
        int get(int x) 
        { 
            return p[p[x].f].ch[1]==x; 
        } 
        int isrt(int x) 
        {
            return !(p[p[x].f].ch[0]==x||p[p[x].f].ch[1]==x);    
        }   
        void pushup(int x) 
        { 
            p[x].size=(x>n);     
            p[x].min=p[x].val; 
            p[x].id=x;     
            if(lson) 
            {
                p[x].size+=p[lson].size;  
                if(p[lson].min<p[x].min) p[x].min=p[lson].min,p[x].id=p[lson].id; 
            }
            if(rson) 
            {
                p[x].size+=p[rson].size;    
                if(p[rson].min<p[x].min) p[x].min=p[rson].min,p[x].id=p[rson].id;     
            }
        }
        void mark(int x) 
        {
            if(x) p[x].rev^=1,swap(lson,rson); 
        }
        void pushdown(int x) 
        {
            if(x&&p[x].rev) 
            {
                p[x].rev=0; 
                if(lson) mark(lson); 
                if(rson) mark(rson);    
            }
        }
        void rotate(int x) 
        {
            int old=p[x].f,fold=p[old].f,which=get(x);    
            if(!isrt(old)) p[fold].ch[p[fold].ch[1]==old]=x;    
            p[old].ch[which]=p[x].ch[which^1],p[p[old].ch[which]].f=old;   
            p[x].ch[which^1]=old,p[old].f=x,p[x].f=fold; 
            pushup(old),pushup(x); 
        }   
        void splay(int x) 
        {
            int u=x,v=0,fa; 
            for(sta[++v]=u;!isrt(u);u=p[u].f) sta[++v]=p[u].f; 
            for(;v;--v) pushdown(sta[v]); 
            for(u=p[u].f;(fa=p[x].f)!=u;rotate(x)) 
                if(p[fa].f!=u) 
                    rotate(get(fa)==get(x)?fa:x);    
        }
        int findroot(int x) 
        {
            Access(x),splay(x);      
            for(;lson;) x=lson;                  
            return x;                   
        }
        void Access(int x) 
        {
            for(int y=0;x;y=x,x=p[x].f) 
                splay(x),rson=y,pushup(x);    
        } 
        void makeroot(int x) 
        {
            Access(x),splay(x),mark(x);   
        } 
        void split(int x,int y) 
        {
            makeroot(x),Access(y),splay(y);    
        }   
        void link(int x,int y) 
        {    
            makeroot(x),p[x].f=y; 
        }  
        void cut(int x,int y)     
        {
            makeroot(x),Access(y),splay(y); 
            p[y].ch[0]=p[x].f=0; 
            pushup(y);        
        }
        #undef lson 
        #undef rson 
    }lct;    
    int vised[N],sum[N];          
    vector<int>Add[N],Del[N];       
    void add_edge(int id) 
    {  
        int u=e[id].u; 
        int v=e[id].v;    
        int now=id+n;    
        if(u==v) 
        {  
            ++sum[e[id].s];  
            --sum[e[id].t]; 
        } 
        else
        {
            if(lct.findroot(u)==lct.findroot(v)) 
            {                                                       
                lct.split(u,v);     
                int cur=lct.p[v].id;     
                if(lct.p[v].size%2==0) 
                {    
                    ++sum[e[id].s];       
                    --sum[min(e[cur-n].t, e[id].t) ];   
                }                                                            
                if(lct.p[cur].val<e[id].t) 
                { 
                    lct.cut(cur, e[cur-n].u);    
                    lct.cut(cur, e[cur-n].v);                       
                    lct.p[now].val=e[id].t;                                           
                    lct.pushup(now);                        
                    lct.link(u,now);                      
                    lct.link(now,v);     
                    vised[cur-n]=1;             
                }                                                                   
            }
            else 
            {
                lct.p[now].val=e[id].t;                     
                lct.pushup(now);        
                lct.link(u,now);  
                lct.link(v,now);           
            }     
        }               
    } 
    void delete_edge(int id) 
    {
        if(vised[id] || e[id].u==e[id].v) return;   
        int u=e[id].u;             
        int v=e[id].v;                    
        lct.cut(id+n,u); 
        lct.cut(id+n,v);           
    }
    int main() 
    {
        int i,j;
        // setIO("input");       
        scanf("%d%d%d",&n,&m,&T);   
        for(i=1;i<=n;++i) lct.p[i].val=inf, lct.pushup(i);     
        for(i=1;i<=m;++i) 
        {
            int u,v,s,t; 
            scanf("%d%d%d%d",&u,&v,&s,&t);    
            e[i]=Edge(u,v,s,t);  
            if(s<t) 
            {   
                Add[s].push_back(i);   
                Del[t].push_back(i);   
            }
        }   
        for(i=0;i<T;++i)  
        {   
            for(j=0;j<(int)Del[i].size();++j) 
            {
                delete_edge(Del[i][j]);        
            }
            for(j=0;j<(int)Add[i].size();++j) 
            {
                add_edge(Add[i][j]); 
            }    
            if(i>0) sum[i]+=sum[i-1];                                                              
            if(sum[i]>0) printf("No
    "); 
            else printf("Yes
    ");        
        } 
        return 0;      
    }                                          
    

      

  • 相关阅读:
    浅谈Oracle12c 数据库、用户、CDB与PDB之间的关系
    ECLIPSE快捷键
    Oracle12cWindows安装、介绍及简单使用(图文)
    金士顿DT100 G3 PS2251-07海力士U盘量产修复成功教程
    tomcat绑定域名
    TCP慢启动、拥塞避免、快速重传、快速恢复
    理解HTTP幂等性
    TCP协议缺陷不完全记录
    Nginx模块开发入门
    一步步构建大型网站架构
  • 原文地址:https://www.cnblogs.com/guangheli/p/11610824.html
Copyright © 2011-2022 走看看