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; 
}

  

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章