JZOJ 5387【GDOI2018模擬9.23】動態圖

題目

Time Limits: 1000 ms Memory Limits: 262144 KB
Description
這裏寫圖片描述

Input

這裏寫圖片描述

Output
這裏寫圖片描述

Sample Input

5 3 0
1 4 5
1 2 4
3 1 2

Sample Output

3

Data Constraint
這裏寫圖片描述

題解

鳥(雀)題一道。。。

做法:函數式線段樹+lct

在每一次加入一條邊i的時候,我們記錄一個last[i]
如果在當前情況下加入了這一條邊之後構成了一個環,last[i]就表示這個環裏面最小的邊的編號(也就是最早加進來的邊),然後我們把這條邊刪除並且把這條邊加進來
如果沒有構成環我們就直接把這一條邊加進來並且last[i]=0
然後對於詢問(l,r),答案就是n減去x∈[l,r] last[x]∈[0,l)的數量
原因就是:
如果last[x]∈[l,x),就表示如果我們依次加入l–r的邊,那麼在加到邊x的時候邊x對應的兩個點已經屬於一個聯通塊了,連上這一條邊並不會減少一個聯通塊,反之則會減少一個聯通塊

對於刪邊,我們發現只會刪去最後一條邊,所以我們可以用一個函數式線段樹來實現這樣的刪除

對於重邊我們需要進行特殊的處理,這個也比較簡單

一開始我判斷兩個點是否在同一個聯通塊的判斷函數打錯了,我天真的以爲和cut是一樣的

後來仔細想了想cut是因爲兩個點之間有邊,換根之後兩個點的深度肯定一個是1一個是2所以這樣打纔是對的,但是判斷函數不是
於是就想到了把x,y都換根一次,看看y換完之後x還是不是根,這樣就可以判斷了

貼代碼

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fo1(i,b,a) for(i=b;i>=a;i--)
#define min(x,y) ((x)<(y)?(x):(y))

using namespace std;

const int maxn=2e6+5;

int tree[maxn*2][4],fa[maxn],son[maxn][3],mi[maxn];
int la[maxn],a[maxn][3],root[maxn],d[maxn];
bool bz[maxn];
int i,j,k,m,n,x,y,q,ty,ans,p,now,z,u,v,o,zsc,l,r;
char ch;

int read(){
    int x=0;
    ch=getchar();
    while (ch<'0' || ch>'9') ch=getchar();
    while (ch>='0' && ch<='9'){
        x=x*10+ch-48;
        ch=getchar();
    }
    return x;
}
bool isroot(int x){
    if (son[fa[x]][1]!=x && son[fa[x]][2]!=x) return true; else return false;
}
void remark(int x){
    if (bz[x]){
        bz[x]=false;
        bz[son[x][1]]^=1;
        bz[son[x][2]]^=1;
        int t=son[x][1];
        son[x][1]=son[x][2]; son[x][2]=t;
    }
}

void update(int x){
    mi[x]=mi[son[x][1]];
    if (mi[son[x][2]] &&(mi[x]==0 || mi[x]>mi[son[x][2]])) mi[x]=mi[son[x][2]];
    if (x>n && (mi[x]==0 || mi[x]>x-n)) mi[x]=x-n;
}
void rotate(int x,int w){
    int y=fa[x];
    son[y][3-w]=son[x][w];
    if (son[x][w]) fa[son[x][w]]=y;
    if (!isroot(y)){
        if (son[fa[y]][1]==y) son[fa[y]][1]=x; else son[fa[y]][2]=x;
    }
    fa[x]=fa[y];
    fa[y]=x;
    son[x][w]=y;
    update(y); update(x);
}   
void splay(int x){
    int i,y;
    d[0]=0;
    while (!isroot(x)){
        d[++d[0]]=x;
        x=fa[x];
    }
    d[++d[0]]=x;
    fo1(i,d[0],1) remark(d[i]);
    x=d[1];
    while (!isroot(x)){
        y=fa[x];
        if (isroot(y)){
            if (x==son[y][1]) rotate(x,2); else rotate(x,1);
        } else{
            if (y==son[fa[y]][1]){
                if (x==son[y][1]){
                    rotate(y,2); rotate(x,2);
                } else{
                    rotate(x,1); rotate(x,2);
                }
            } else{
                if (x==son[y][2]){
                    rotate(y,1); rotate(x,1);
                } else{
                    rotate(x,2); rotate(x,1);
                }
            }
        }
    }
}
void access(int x){
    for(int t=0;x;x=fa[x]) splay(x),son[x][2]=t,update(x),t=x;
}
void makeroot(int x){
    access(x); splay(x); bz[x]^=1;
}
void link(int x,int y){
    makeroot(x); fa[x]=y;
}
void cut(int x,int y){
    makeroot(x); access(y); splay(y); son[y][1]=0; fa[x]=0; update(y);
}
int find(int x,int y){
    makeroot(x); access(y); splay(y); return mi[y];
}
bool tong(int x,int y){
    makeroot(x); makeroot(y);
    if (isroot(x)) return false; else return true;
}
void maketree(int v,int l,int r,int x){
    tree[++p][1]=tree[v][1]; tree[p][2]=tree[v][2]; tree[p][3]=tree[v][3]+1;
    if (l==r) return;
    int mid=(l+r)/2;
    if (x<=mid){
        tree[p][1]=p+1;
        maketree(tree[v][1],l,mid,x);
    } else{
        tree[p][2]=p+1;
        maketree(tree[v][2],mid+1,r,x);
    }
}
void find(int zo,int yo,int l,int r,int x,int y){
    if (l==x && r==y){
        z=z+tree[yo][3]-tree[zo][3];
    } else{
        int mid=(l+r)/2;
        if (y<=mid) find(tree[zo][1],tree[yo][1],l,mid,x,y); else
        if (x>mid) find(tree[zo][2],tree[yo][2],mid+1,r,x,y); else{
            find(tree[zo][1],tree[yo][1],l,mid,x,mid);
            find(tree[zo][2],tree[yo][2],mid+1,r,mid+1,y);
        }
    }
}
int main(){
    freopen("graph.in","r",stdin);
    freopen("graph.out","w",stdout);
    n=read(); q=read(); ty=read();
    fo(zsc,1,q){
        z=read();
        if (z==1){
            u=read(); v=read(); if (ty){
                u=1+(u xor ans)%n; v=1+(v xor ans)%n;
            }
            ++now;
            a[now][1]=u; a[now][2]=v;
            if (u==v){
                root[now]=root[now-1];
                continue;
            }
            if (! tong(u,v)){
                mi[now+n]=now;
                link(u,now+n); link(v,now+n);
            } else{
                o=find(u,v);
                la[now]=o;
                cut(o+n,a[o][1]);
                cut(o+n,a[o][2]);
                mi[now+n]=now;
                link(u,now+n);
                link(v,now+n);
            }
            root[now]=p+1;
            maketree(root[now-1],0,q,la[now]);
            a[now][1]=u; a[now][2]=v;
        } else if (z==2){
            if (a[now][1]==a[now][2]){
                now--;
                continue;
            }
            cut(n+now,a[now][1]);
            cut(n+now,a[now][2]);
            if (la[now]){
                mi[la[now]+n]=la[now];
                link(a[la[now]][1],la[now]+n);
                link(a[la[now]][2],la[now]+n);
            }
            la[now]=0;
            now--;
        } else{
            x=read(); y=read();
            if (ty){
                u=1+(x xor ans)%now; v=1+(y xor ans)%now;
                x=min(u,v);
                y=max(u,v);
            }
            z=0;
            find(root[x-1],root[y],0,q,0,x-1);
            ans=n-z;
            printf("%d\n",ans);
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章