1. 程式人生 > >[ZJOI2007]捉迷藏 (點分樹+堆*3)

[ZJOI2007]捉迷藏 (點分樹+堆*3)

點分樹一點都不會啊(還是太菜了)
點分樹就是我們點分治構成的新樹。滿足深度很小。
然後我們就可以在上面瞎維護東西了。
三個大根堆:
\(C[u]\)裡裝的是點分樹中u的子樹所有點到點分樹中u的父親的距離。
\(B[u]\)裡裝的是點分樹中u的所有兒子的C的最大值。
\(A\)裡裝的是所有\(B\)的最大值與次大值之和。
\(A\)的堆頂就是答案。
(我一開始一直以為兩個堆就行,對第三個對錶示疑惑,又懶得深入想,一直翻題解。千萬不能犯懶不想啊)
我們找答案可以快速找到。問題是怎麼維護?
因為我們是點分樹,深度小,可以直接一個一個跳到根暴力修改維護。具體一些就是設刪的點為\(x\),跳到一個點\(u\)

\(x\)的貢獻從\(C[u]\)中刪掉,然後重新跟新\(B[u]\)\(A\)
至此本題得到解決,就是我程式碼常數太大。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
const int N=200100;
struct que{
    priority_queue<int> x,y;
    inline void push(int a){x.push(a);}
    inline void del(int a){y.push(a);}
    inline int top(){while(y.size()&&x.top()==y.top())x.pop(),y.pop();return x.top();}
    inline int size(){return x.size()-y.size();}
    inline void pop(){while(y.size()&&x.top()==y.top())x.pop(),y.pop();x.pop();}
    inline int sectop(){int a=top();pop();int b=top();push(a);return b;}
}A,B[N],C[N];
int cnt,head[N];
int light[N],tot,n,m;
int root,size[N],g[N],vis[N],all,f[N];
int dep[N],mn[N*2][24],num,dfn[N];
int Log[N];
struct edge{
    int to,nxt;
}e[N*2];
inline void add_edge(int u,int v){
    cnt++;
    e[cnt].nxt=head[u];
    e[cnt].to=v;
    head[u]=cnt;
}
inline void dfs(int u,int f){
    dfn[u]=++num;
    dep[u]=dep[f]+1;
    mn[num][0]=dep[u];
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(v==f)continue;
        dfs(v,u);
        mn[++num][0]=dep[u];
    }
}
inline void getroot(int u,int f){
    g[u]=0;size[u]=1;
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(v==f||vis[v])continue;
        getroot(v,u);
        g[u]=max(g[u],size[v]);
        size[u]+=size[v];
    }
    g[u]=max(g[u],all-size[u]);
    if(g[u]<g[root])root=u;
}
inline int getdep(int x,int y){
    int a=dfn[x];
    int b=dfn[y];
    if(a>b)swap(a,b);
    int len=Log[b-a+1];
    return min(mn[a][len],mn[b-(1<<len)+1][len]);
}
inline int dis(int x,int y){
    return dep[x]+dep[y]-2*getdep(x,y);
}
inline void work(int u,int ff){
    C[root].push(dis(u,f[root]));
    size[u]=1;
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(v==ff||vis[v])continue;
        work(v,u);
        size[u]+=size[v];
    }
}
inline void pusha(int x){
    if(B[x].size()>=2)A.push(B[x].top()+B[x].sectop());
}
inline void dela(int x){
    if(B[x].size()>=2)A.del(B[x].top()+B[x].sectop());
}
inline void build(int u,int ff){
    f[u]=ff;vis[u]=1;
    B[u].push(0);
    work(u,0);
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(vis[v])continue;
        root=0,all=size[v];
        getroot(v,0);
        v=root;
        build(root,u);
        B[u].push(C[v].top());
    }
    pusha(u);
}
inline void on(int x){
    dela(x);
    B[x].del(0);
    pusha(x);
    for(int i=x;f[i];i=f[i]){
        dela(f[i]);
        B[f[i]].del(C[i].top());
        C[i].del(dis(x,f[i]));
        if(C[i].size())B[f[i]].push(C[i].top());
        pusha(f[i]);
    }
}
inline void off(int x){
    dela(x);
    B[x].push(0);
    pusha(x);
    for(int i=x;f[i];i=f[i]){
        dela(f[i]);
        if(C[i].size())B[f[i]].del(C[i].top());
        C[i].push(dis(x,f[i]));
        B[f[i]].push(C[i].top());
        pusha(f[i]);
    }
}
void prework(){
    for(int j=1;j<=Log[num];j++)
        for(int i=1;i+(1<<j)-1<=num;i++)
            mn[i][j]=min(mn[i][j-1],mn[i+(1<<(j-1))][j-1]);
}
inline int read(){
    int sum=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
    return sum*f;
}
int main(){
    n=read();
    Log[0]=-1;for(int i=1;i<=200000;i++)Log[i]=Log[i>>1]+1;
    for(int i=1;i<n;i++){
        int u=read(),v=read();
        add_edge(u,v);add_edge(v,u);
    }
    dfs(1,0);
    prework();
    g[0]=n;root=0;all=n;
    getroot(1,0);build(root,0);
    tot=n;
    m=read();
    char s;
    while(m--){
        s=getchar();
        if(s=='G'){
            if(tot<=1)printf("%d\n",tot-1);
            else printf("%d\n",A.top());
        }
        else{
            int x=read();
            if(light[x]==0)on(x),tot--;
            else off(x),tot++;
            light[x]^=1;
        }
    }
    return 0;
}