bzoj 1095

动态点分治做法;
更新一个点只会影响一条log的链,信息用三个堆维护;
点分治作为复杂度保证

#include<bits/stdc++.h>
#define rep(i,k,n) for(int i=k;i<=n;i++)
#define inf 0x7f7f7f7f
using namespace std;
const int N=100005;
struct heap{
    priority_queue<int> A,B;
    void push(int x){A.push(x);}

    void erase(int x){B.push(x);}

    void pop(){
        while(B.size() && A.top()==B.top()){A.pop();B.pop();}
        A.pop();
    }
    int top(){
        while(B.size() && A.top()==B.top()){A.pop();B.pop();}
        if(!A.size())return 0;
        return A.top();
    }
    int size(){
        return A.size()-B.size();
    }
    int step(){
        if(size()<2)return 0;
        int x=top();pop();
        int y=top();push(x);
        return y;

    }
}A,B[N],C[N];
int head[N],s[N],vis[N],dep[N],fa[N],q[3*N][20],bin[20],Log[2000005],sum,size,tot=0,n,Q,dfn=0,pos[N],root,c[N],black;
struct E{int to,next;E(int to=0,int next=0):to(to),next(next){}}edge[3*N];
void add(int x,int y){
    edge[++tot]=E(y,head[x]);head[x]=tot;
    edge[++tot]=E(x,head[y]);head[y]=tot;
}
void dfs(int x,int f){
    dep[x]=dep[f]+1;
    q[++dfn][0]=dep[x];
    pos[x]=dfn;
    for(int i=head[x];i;i=edge[i].next){
        int v=edge[i].to;
        if(v!=f)dfs(v,x);
        q[++dfn][0]=dep[x];              ////euler!每个结点出现其度数+1次; 
    }
}
void init(){
    rep(i,1,19)rep(j,1,dfn-bin[i]+1)q[j][i]=min(q[j][i-1],q[j+bin[i-1]][i-1]);
}
inline int rmp(int x,int y){
    x=pos[x],y=pos[y];if(x>y)swap(x,y);
    int j=Log[y-x+1];
    return min(q[x][j],q[y-bin[j]+1][j]);
}
int dist(int x,int y){
    return dep[x]+dep[y]-2*rmp(x,y);
}
void getroot(int x,int f){
    s[x]=1;int kk=0;
    for(int i=head[x];i;i=edge[i].next){
        int v=edge[i].to;
        if(!vis[v] && v!=f)
        {getroot(v,x);
        kk=max(kk,s[v]);
        s[x]+=s[v];
    }
    }
    kk=max(kk,sum-s[x]);
    if(kk<size){size=kk;root=x;}
}
void build(int x){vis[x]=1;
    for(int i=head[x];i;i=edge[i].next){
        int v=edge[i].to;
        if(!vis[v]){
            size=inf,sum=s[v];
            getroot(v,x);
            fa[root]=x;
            build(root);
        }
    }
}
void turn_off(int u,int v){
    if(u==v){
        B[u].push(0);
        if(B[u].size()==2)A.push(B[u].top());
    }
    if(!fa[u])return;
    int f=fa[u],dis=dist(f,v),tmp=C[u].top();  //C中维护最长链+1 
    C[u].push(dis);
    if(dis>tmp){
        int mx=B[f].top()+B[f].step();int sb=B[f].size();
        if(tmp)B[f].erase(tmp);
        B[f].push(dis);
        int nx=B[f].top()+B[f].step();
        if(nx>mx){
            if(sb>=2)A.erase(mx);
            if(B[f].size()>=2)A.push(nx);
    }
    }
    turn_off(f,v);
}
void turn_on(int u,int v){
    if(u==v){
        if(B[u].size()==2)A.erase(B[u].top());
        B[u].erase(0);
    }
    if(!fa[u])return;
    int f=fa[u],dis=dist(f,v);
    int tmp=C[u].top();  
    C[u].erase(dis);
    if(dis==tmp){
        int mx=B[f].top()+B[f].step();
        int sb=B[f].size();
        B[f].erase(dis);
        if(C[u].top())B[f].push(C[u].top());
        int nx=B[f].top()+B[f].step();
        if(nx<mx)
        {
            if(sb>=2)A.erase(mx);
            if(B[f].size()>=2)A.push(nx);  
        }
    }
    turn_on(f,v);
}

int main(){
//  freopen("in.in","r",stdin);
//  freopen("out.out","w",stdout);
    scanf("%d",&n);
    int x,y;
    rep(i,1,n-1){scanf("%d%d",&x,&y);add(x,y);}

    bin[0]=1;rep(i,1,19)bin[i]=bin[i-1]<<1;
    Log[0]=-1;rep(i,1,2000000)Log[i]=Log[i>>1]+1;
    dfs(1,0);init();

    size=inf,sum=n;
    getroot(1,0);
    build(root);

    rep(i,1,n)
    {c[i]=1,C[i].push(0);}
    rep(i,1,n)
    turn_off(i,i);
    black=n;
    scanf("%d",&Q);char ss[20];
    while(Q--){
        scanf("%s",ss);
        if(ss[0]=='C'){
            scanf("%d",&x);
            if(c[x]){turn_on(x,x),black--;}
            else turn_off(x,x),black++;
            c[x]^=1;
        }
        else{
            if(black<=1)printf("%d\n",black-1);
            else printf("%d\n",A.top());
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值