P2056 [ZJOI2007]捉迷藏 (线段树分治做法)

· · 个人记录

#include <bits/stdc++.h>
using namespace std;
const int N=6e5+9;
int head[N],nxt[N],go[N],sze,n,m;

char read_char(){
    char ch=getchar();
    while(ch!='G'&&ch!='C') ch=getchar();
    return ch;
}

void add_edge(int u,int v){
    ++sze;nxt[sze]=head[u];head[u]=sze;go[sze]=v;
}

int dep[N],siz[N],son[N],top[N],fat[N],tot;

void dfs1(int id,int fa){
    siz[id]=1;dep[id]=dep[fa]+1;fat[id]=fa;
    for(int i=head[id];i;i=nxt[i]){
        int to=go[i];
        if(to==fa)continue;
        dfs1(to,id);
        siz[id]+=siz[to];
        if(siz[to]>siz[son[id]]) son[id]=to;
    }
}

void dfs2(int id,int fa){
    if(son[id]){
        top[son[id]]=top[id];
        dfs2(son[id],id);
    }
    for(int i=head[id];i;i=nxt[i]){
        int to=go[i];
        if(to==fa||to==son[id]) continue;
        top[to]=to;
        dfs2(to,id);
    }
}

int LCA(int x,int y){
    int fx=top[x],fy=top[y];
    while(fx!=fy){
        if(dep[fx]<dep[fy]) swap(x,y),swap(fx,fy);
        x=fat[fx];
        fx=top[x];
    }
    if(dep[x]<dep[y]) return x;
    else return y;
}

int cnt;
int hh[N<<2],nx[N*30],da[N*30],szz;         //链表 
int who[N];        //该时间有没有询问
int ans[N],pre[N];      //答案,上一次修改时间 

void modefy(int id,int l,int r,int x,int y,int c){
    if(x>y) return;
    if(x<=l&&r<=y){
        ++szz;
        nx[szz]=hh[id];
        hh[id]=szz;
        da[szz]=c;
        return;
    }
    int mid=(l+r)>>1;
    if(x<=mid) modefy(id<<1,l,mid,x,y,c);
    if(mid<y) modefy(id<<1|1,mid+1,r,x,y,c); 
}

void dfs(int id,int l,int r,int x,int y){
    for(int i=hh[id];i;i=nx[i]){
        int p=da[i];
        if(!x) x=p;
        else if(!y) y=p;
        else{
            int d1=dep[x]+dep[p]-2*dep[LCA(x,p)],
                d2=dep[y]+dep[p]-2*dep[LCA(y,p)],
                d3=dep[x]+dep[y]-2*dep[LCA(x,y)];
            if(d1<d2){
                swap(x,y);
                swap(d1,d2);
            }
            if(d1>d3) y=p;
        }
    }
    if(l==r){
        if(who[l]){
            if(!x) ans[who[l]]=-1;
            else if(!y) ans[who[l]]=0;
            else ans[who[l]]=dep[x]+dep[y]-2*dep[LCA(x,y)];
        } 
        return;
    }
    int mid=(l+r)>>1;
    dfs(id<<1,l,mid,x,y);
    dfs(id<<1|1,mid+1,r,x,y);
}

int main(){
    scanf("%d",&n);
    for(int i=1;i<n;++i){
        int u,v;
        scanf("%d%d",&u,&v);
        add_edge(u,v);
        add_edge(v,u);
    }
    dfs1(1,0);
    top[1]=1;
    dfs2(1,0);
    scanf("%d",&m);
    for(int i=1;i<=n;++i)
    pre[i]=1;
    for(int i=1;i<=m;++i){
        char op=read_char();
        if(op=='G'){
            who[i]=++cnt;
        }
        else {
            int x;scanf("%d",&x);
            if(!pre[x]) pre[x]=i;
            else {
                modefy(1,1,m,pre[x],i-1,x);
                pre[x]=0;
            }
        }
    }
    for(int i=1;i<=n;++i)
    if(pre[i]) modefy(1,1,m,pre[i],m,i);
    dfs(1,1,m,0,0);
    for(int i=1;i<=cnt;++i)
    printf("%d\n",ans[i]);
    return 0;
}