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;
		}
	}
}
posted @ 2019-12-31 14:27  白木偶君  阅读(142)  评论(0编辑  收藏  举报