【ZJOI2007】—捉迷藏(动态点分治)
网上主要做法有2种:
1、括号序列(然而我并不会)
简单的动态点分治
建出点分树之后每次修改就是了
实现的时候维护三个堆
全局一个堆,维护答案最大值,存每个堆B的最大值和次大值之和
每个重心存各个子树最大值,即子结点堆C的最大值
每个重心存所有子树到其距离
然后每次查询中最大值就可以了
然后我们用欧拉序+表维护
复杂度
常数较大,不吸氧很容易
#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;
}
}
}