zoukankan      html  css  js  c++  java
  • CF1386C Joker 双指针+动态树

    双指针+LCT.     

    在二分图那道题中,有一种用 LCT 维护奇环的方法.   

    该题的做法和那道题相似.      

    对于 $i$,维护 $left[i]$ 表示当删除 $i$ 时最靠左的端点使得删掉 $[left[i]+1,i]$ 后仍然存在奇环.      

    那么最后判断答案的时候就看 $(l,r)$ 中的 $l$ 是否大于 $left[r]$ 即可.       

    由于删掉边一定不会使答案更优,所以 $i$ 增加时 $left[i]$ 不会减小,故 $[left[i],i]$ 满足双指针性质(即不存在包含的情况)   

    将边分为两类:

    1. 由于 $i$ 变大被删掉的. 

    2. 由于双指针中左端点的移动被加入的.    

    显然对于 $1$ 类边希望出现时间越晚越好,对于 $2$ 类边没有要求.   

    根据上述结论,我们在预处理边的时候贪心加入即可(即加不进去就不加)     

    然后双指针移动的时候去替换结束时间最小的边,类似最大生成树.          

    #include <cstdio>  
    #include <cstring>
    #include <algorithm>
    #define N 400008  
    #define ll long long  
    #define ls s[x].ch[0] 
    #define rs s[x].ch[1] 
    #define setIO(s) freopen(s".in","r",stdin) 
    using namespace std;    
    const int inf=100000000;   
    int det[N]; 
    int left[N],sta[N<<1],vis[N<<1],n,m,Q;    
    struct Edge {   
        int u,v,t;         
        Edge(int u=0,int v=0,int t=0):u(u),v(v),t(t){}  
    }a[N],arr[N]; 
    struct data {  
        int ch[2],rev,f,v,id,si,t;       
    }s[N<<2];  
    inline int get(int x) { return s[s[x].f].ch[1]==x; } 
    inline int isr(int x) { return s[s[x].f].ch[0]!=x&&s[s[x].f].ch[1]!=x; }   
    void pushup(int x) {      
        s[x].id=x;     
        s[x].si=(x<=n)+s[ls].si+s[rs].si;      
        if(ls&&s[s[ls].id].t<s[s[x].id].t) { 
            s[x].id=s[ls].id; 
        }  
        if(rs&&s[s[rs].id].t<s[s[x].id].t) { 
            s[x].id=s[rs].id;   
        }  
    }
    void mark(int x) { 
        s[x].rev^=1,swap(ls,rs);  
    }  
    void pushdown(int x) { 
        if(s[x].rev) {  
            if(ls) mark(ls); 
            if(rs) mark(rs); 
            s[x].rev=0; 
        } 
    }    
    void rotate(int x) {  
        int old=s[x].f,fold=s[old].f,which=get(x); 
        if(!isr(old)) { 
            s[fold].ch[s[fold].ch[1]==old]=x;  
        }  
        s[old].ch[which]=s[x].ch[which^1];  
        if(s[old].ch[which]) s[s[old].ch[which]].f=old;  
        s[x].ch[which^1]=old,s[old].f=x,s[x].f=fold;  
        pushup(old),pushup(x);  
    } 
    void splay(int x) { 
        int u=x,v=0,fa; 
        for(sta[++v]=u;!isr(u);u=s[u].f) { 
            sta[++v]=s[u].f;  
        }    
        for(;v;--v) pushdown(sta[v]);  
        for(u=s[u].f;(fa=s[x].f)!=u;rotate(x))  
            if(s[fa].f!=u) { 
                rotate(get(fa)==get(x)?fa:x);  
            }
    }
    void access(int x) { 
        for(int y=0;x;y=x,x=s[x].f) {    
            splay(x),rs=y,pushup(x);  
        }
    }   
    void makert(int x) {
        access(x),splay(x),mark(x);  
    }      
    void split(int x,int y) {  
        makert(x),access(y),splay(y);  
    }   
    int find(int x) {  
        access(x),splay(x);          
        while(ls) pushdown(x),x=ls; 
        splay(x);  
        return x;  
    }
    void ADD(int x,int y) { 
        makert(x),s[x].f=y; 
    }
    void DEC(int x,int y) {   
        makert(x),access(y),splay(y);  
        s[y].ch[0]=s[x].f=0;  
        pushup(y);  
    }
    void exi(int lst) { 
        if(lst==0) { 
            for(int i=1;i<=Q;++i) {     
                int x,y;  
                scanf("%d%d",&x,&y); 
                printf("NO
    "); 
            } 
            exit(0); 
        }
    }        
    int main() { 
        // setIO("input");           
        int x,y,z; 
        scanf("%d%d%d",&n,&m,&Q);   
        for(int i=1;i<=m;++i) { 
            scanf("%d%d",&x,&y);  
            arr[i]=Edge(x,y,i);  
        }         
        int lst=0;         
        a[0].t=inf;  
        for(int i=1;i<=n;++i) { 
            s[i].t=inf;   
            s[i].id=i; 
        }
        for(int i=m;i>=1;--i) {      
            x=arr[i].u;   
            y=arr[i].v;      
            a[i]=arr[i];  
            if(find(x)==find(y)) {   
                split(x,y);        
                if(s[y].si&1) {    
                    lst=i;   
                    break;   
                }
            }
            else {    
                int now=n+i;         
                s[now].v=i;        
                s[now].t=i;     
                pushup(now); 
                vis[i]=1;    
                ADD(x,now),ADD(y,now);  
            }
        }         
        int tot=n+m;  
        exi(lst);     
        int p=1,cnt=0; 
        for(int i=lst;i<=m;++i) {           
            int flag=0;      
            for(cnt+=det[i];!cnt&&p<=i;++p) {              
                a[m+p]=arr[p];  
                x=arr[p].u,y=arr[p].v;   
                if(find(x)==find(y)) {     
                    split(x,y);     
                    int pr=s[y].id; 
                    int nx=s[pr].v;        
                    if(s[y].si&1) {        
                        ++cnt,--det[a[nx].t];            
                    }                   
                    if(a[nx].t<=m) {     
                        vis[s[y].id-n]=0; 
                    }     
                    DEC(pr,a[nx].u); 
                    DEC(pr,a[nx].v);                    
                }               
                int now=++tot;  
                a[m+p].t=m+1;         
                s[now].v=m+p;   
                s[now].t=m+1;    
                pushup(now),ADD(now,x),ADD(now,y);                 
            }          
            left[i]=p-1;                             
            if(i+1<=m&&vis[i+1]) {   
                vis[i+1]=0;    
                int now=i+1+n;  
                DEC(now,arr[i+1].u); 
                DEC(now,arr[i+1].v);         
            }
        }
        for(int i=1;i<=Q;++i) { 
            scanf("%d%d",&x,&y);   
            if(y<lst) { 
                printf("YES
    "); 
            }  
            else { 
                if(x>left[y]) printf("YES
    ");   
                else printf("NO
    "); 
            } 
        }
        return 0; 
    }
    

      

  • 相关阅读:
    【LeetCode】17. Letter Combinations of a Phone Number
    【LeetCode】16. 3Sum Closest
    【LeetCode】15. 3Sum 三个数和为0
    【LeetCode】14. Longest Common Prefix 最长前缀子串
    【LeetCode】13. Roman to Integer 罗马数字转整数
    【LeetCode】12. Integer to Roman 整型数转罗马数
    【LeetCode】11. Container With Most Water
    【LeetCode】10. Regular Expression Matching
    Models of good programmer
    RSA Algorithm
  • 原文地址:https://www.cnblogs.com/guangheli/p/13404307.html
Copyright © 2011-2022 走看看