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;
}
}
}
不以物喜,不以己悲