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\n"); 
        else printf("Yes\n");        
    } 
    return 0;      
}                                          

  

posted @ 2019-09-30 08:04  EM-LGH  阅读(168)  评论(0编辑  收藏  举报