【ZJOI2007】—捉迷藏(动态点分治)

传送门

网上主要做法有2种:

1、括号序列(然而我并不会)

简单的动态点分治

建出点分树之后每次lognlogn修改就是了

实现的时候维护三个堆
A:A:全局一个堆,维护答案最大值,存每个堆B的最大值和次大值之和
B:B:每个重心存各个子树最大值,即子结点堆C的最大值
C:C:每个重心存所有子树到其距离

然后每次查询AA中最大值就可以了

然后我们用欧拉序+STST表维护LcaLca

复杂度O(nlog2n+mlog2n)O(nlog^2n+mlog^2n)

STLSTL常数较大,不吸氧很容易TT

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	char ch=getchar();
	int res=0,f=1;
	while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
	while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
	return res*f;
}
#define ll long long
const int N=100005;
int two[20],Log[200005];
int n,m,rt,tot;
int siz[N],fa[N],dep[N],cnt,maxn,son[N],adj[N],nxt[N<<1],to[N<<1];
int st[18][N<<1],pos[N],dfn;
bool vis[N],op[N];
inline void addedge(int u,int v){
	nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v;
}
struct Stargazer{
	priority_queue<int>A,B;
	inline void push(int x){
		A.push(x);
	}
	inline void erase(int x){
		B.push(x);
	}
	inline void pop(){
		while(B.size()&&A.top()==B.top())
			A.pop(),B.pop();
		A.pop();
	}
	inline int top(){
		while(B.size()&&A.top()==B.top())
			A.pop(),B.pop();
		if(!A.size())return 0;
		return A.top();
	}
	inline int size(){
		return A.size()-B.size();
	}
	inline int sec(){
		if(size()<2)return 0;
		int x=top();pop();
		int y=top();push(x);
		return y;
	}
}A,B[N],C[N];
inline void init(){
	two[0]=1,Log[0]=-1;
	for(int i=1;i<20;++i)two[i]=two[i-1]*2;
	for(int i=1;i<=200000;++i)Log[i]=Log[i>>1]+1;
}
void dfs(int u,int f){
	st[0][++dfn]=dep[u];
	pos[u]=dfn;
	for(int e=adj[u];e;e=nxt[e]){
		int v=to[e];
		if(v==f)continue;
		dep[v]=dep[u]+1;
		dfs(v,u);
		st[0][++dfn]=dep[u];
	}
}
inline void pre(){
	for(int i=1;i<=Log[dfn];++i)
		for(int j=1;j<=dfn;++j)
			if(j+two[i]-1<=dfn)
				st[i][j]=min(st[i-1][j],st[i-1][j+two[i-1]]);
}
void getrt(int u,int fa){
	siz[u]=1,son[u]=0;
	for(int e=adj[u];e;e=nxt[e]){
		int v=to[e];
		if(v==fa||vis[v])continue;
		getrt(v,u);
		siz[u]+=siz[v];
		son[u]=max(son[u],siz[v]);
	}
	son[u]=max(son[u],maxn-siz[u]);
	if(son[u]<son[rt])rt=u;
}
void solve(int u,int f){
	fa[u]=f,vis[u]=1;
	for(int e=adj[u];e;e=nxt[e]){
		int v=to[e];
		if(vis[v])continue;
		maxn=siz[v],rt=0;
		getrt(v,u);
		solve(rt,u);
	}
}
inline int lca(int u,int v){
	u=pos[u],v=pos[v];
	if(v<u)swap(v,u);
	int L=Log[v-u+1];
	return min(st[L][u],st[L][v-two[L]+1]);
}
inline int dis(int u,int v){
	return dep[u]+dep[v]-2*lca(u,v);
}
void 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].sec(),si=B[f].size();
		if(tmp)B[f].erase(tmp);
		B[f].push(d);int now=B[f].top()+B[f].sec();
		if(now>mx){
			if(si>=2)A.erase(mx);
			if(B[f].size()>=2)A.push(now);
		}
	}
	off(f,v);
}
void 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].sec(),si=B[f].size();
		B[f].erase(d);
		if(C[u].top())B[f].push(C[u].top());
		int now=B[f].top()+B[f].sec();
		if(now<mx){
			if(si>=2)A.erase(mx);
			if(B[f].size()>=2)A.push(now);
		}
	}
	on(f,v);
}
int main(){
	init();
	n=read();
	for(int i=1;i<n;++i){
		int u=read(),v=read();
		addedge(u,v),addedge(v,u);
	}
	dfs(1,0);
	pre();
	son[0]=maxn=n;
	getrt(1,rt=0),solve(rt,0);
	for(int i=1;i<=n;i++)C[i].push(0);
	for(int i=1;i<=n;i++)op[i]=1;
	for(int i=1;i<=n;++i)
		off(i,i),++tot;
	char c[5];m=read();
	for(int i=1;i<=m;++i){
		scanf("%s",c);
		if(c[0]=='G'){
			if(tot<=1)cout<<(tot-1)<<'\n';
			else cout<<A.top()<<'\n';
		}
		else{
			int u=read();
			if(op[u])on(u,u),--tot;
			else off(u,u),++tot;
			op[u]^=1;
		}
	}
}
posted @ 2019-01-16 12:31  Stargazer_cykoi  阅读(99)  评论(0编辑  收藏  举报