其他分享
首页 > 其他分享> > CF1386C Joker 双指针+动态树

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\n"); 
        } 
        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\n"); 
        }  
        else { 
            if(x>left[y]) printf("YES\n");   
            else printf("NO\n"); 
        } 
    }
    return 0; 
}

  

 

标签:int,CF1386C,Joker,define,lst,left,now,指针
来源: https://www.cnblogs.com/guangheli/p/13404307.html