luogu P2056 [ZJOI2007]捉迷藏 |动态点分治

题目描述

Jiajia 和 Wind 是一对恩爱的夫妻,并且他们有很多孩子。某天,Jiajia、Wind 和孩子们决定在家里玩捉迷藏游戏。他们的家很大且构造很奇特,由 NNN 个屋子和 N−1N-1N−1 条双向走廊组成,这 N−1N-1N−1 条走廊的分布使得任意两个屋子都互相可达。

游戏是这样进行的,孩子们负责躲藏,Jiajia 负责找,而 Wind 负责操纵这 NNN 个屋子的灯。在起初的时候,所有的灯都没有被打开。每一次,孩子们只会躲藏在没有开灯的房间中,但是为了增加刺激性,孩子们会要求打开某个房间的电灯或者关闭某个房间的电灯。为了评估某一次游戏的复杂性,Jiajia 希望知道可能的最远的两个孩子的距离(即最远的两个关灯房间的距离)。

我们将以如下形式定义每一种操作:

C(hange) i 改变第 iii 个房间的照明状态,若原来打开,则关闭;若原来关闭,则打开。
G(ame) 开始一次游戏,查询最远的两个关灯房间的距离。

输入格式

第一行包含一个整数 NNN,表示房间的个数,房间将被编号为 1,2,3…N1,2,3…N1,2,3…N 的整数。

接下来 N−1N-1N−1 行每行两个整数 aaa, bbb,表示房间 aaa 与房间 bbb 之间有一条走廊相连。

接下来一行包含一个整数 QQQ,表示操作次数。接着 QQQ 行,每行一个操作,如上文所示。

输出格式

对于每一个操作 Game,输出一个非负整数,表示最远的两个关灯房间的距离。若只有一个房间是关着灯的,输出 0;若所有房间的灯都开着,输出 -1。


#include<queue>
#include<cstdio>
#define inf 1000000000
#define mod 1000000007
#define pa pair<int,int>
#define ll long long 
using namespace std;
inline int read(){
    int x=0;char ch=getchar();
    while(ch<'0'||ch>'9'){ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x;
}
int bin[20],Log[200005];
int n,m,G,cnt,dfn,sum,tot;
int size[100005],f[100005],deep[100005],last[100005];
int mn[18][200005],pos[100005],fa[100005];
bool vis[100005],clo[100005];
struct edge{
    int to,next;
}e[200005];
inline void insert(int u,int v){
    e[++cnt]=(edge){v,last[u]};last[u]=cnt;
    e[++cnt]=(edge){u,last[v]};last[v]=cnt;
}
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 stop(){
        if(size()<2)return 0;
        int x=top();pop();
        int y=top();push(x);
        return y;
    }
}A,B[100005],C[100005];
inline void dfs(int x,int fa){
    mn[0][++dfn]=deep[x];
    pos[x]=dfn;
    for(int i=last[x];i;i=e[i].next){
        int v=e[i].to;
        if(v==fa)continue;
        deep[v]=deep[x]+1;
        dfs(v,x);
        mn[0][++dfn]=deep[x];
    }
}
inline void getrt(int x,int fa){
    size[x]=1; f[x]=0;
    for(int i=last[x];i;i=e[i].next){
        int v=e[i].to;
        if(v==fa||vis[v])continue;
        getrt(v,x);
        size[x]+=size[v];
        f[x]=max(f[x],size[v]);
    }
    f[x]=max(f[x],sum-size[x]);
    if(f[x]<f[G])G=x;
}
inline void divi(int x,int f){
    fa[x]=f; vis[x]=1;
    for(int i=last[x];i;i=e[i].next){
        int v=e[i].to;
        if(vis[v])continue;
        sum=size[v]; G=0; getrt(v,x);
        divi(G,x);
    }
}
inline int rmq(int x,int y){
    x=pos[x]; y=pos[y];
    if(y<x)swap(x,y);
    int t=Log[y-x+1];
    return min(mn[t][x],mn[t][y-bin[t]+1]);
}
inline int dis(int x,int y){
    return deep[x]+deep[y]-2*rmq(x,y);
}
inline 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],D=dis(f,v),tmp=C[u].top();
    C[u].push(D);
    if(D>tmp){
        int mx=B[f].top()+B[f].stop(),size=B[f].size();
        if(tmp)B[f].erase(tmp);
        B[f].push(D);
        int now=B[f].top()+B[f].stop();
        if(now>mx){
            if(size>=2)A.erase(mx);
            if(B[f].size()>=2)A.push(now);
        }
    }
    turn_off(f,v);
}
inline 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],D=dis(f,v),tmp=C[u].top();
    C[u].erase(D);
    if(D==tmp){
        int mx=B[f].top()+B[f].stop(),size=B[f].size();
        B[f].erase(D);
        if(C[u].top())B[f].push(C[u].top());
        int now=B[f].top()+B[f].stop();
        if(now<mx){
            if(size>=2)A.erase(mx);
            if(B[f].size()>=2)A.push(now);
        }
    }
    turn_on(f,v);
}
int main(){
    register int i,j;
    bin[0]=1; for(i=1;i<20;i++)bin[i]=bin[i-1]<<1;
    Log[0]=-1; for(i=1;i<=200000;i++)Log[i]=Log[i>>1]+1;
    n=read();
    for(i=1;i<n;i++)insert(read(),read());
    dfs(1,0);
    for(i=1;i<=Log[dfn];i++) for(j=1;j<=dfn;j++)
    mn[i][j]=min(mn[i-1][j],mn[i-1][j+bin[i-1]]);
    G=0; f[0]=inf; sum=n;
    getrt(1,0); divi(G,0);
    for(i=1;i<=n;i++)C[i].push(0);
    for(i=1;i<=n;i++)clo[i]=1;
    for(i=1;i<=n;i++){
        turn_off(i,i);
        tot++;
    }
    char ch[2];
    m=read();
    while(m--){
        scanf("%s",ch+1);
        if(ch[1]=='G'){
            if(tot<=1)printf("%d\n",tot-1);
            else printf("%d\n",A.top());
        }else {
            int x=read();
            if(clo[x])turn_on(x,x),tot--;
            else turn_off(x,x),tot++;
            clo[x]^=1;
        }
    }
}

猜你喜欢

转载自www.cnblogs.com/naruto-mzx/p/12124252.html