P2056 [ZJOI2007]捉迷藏
思路:动态点分治
提交:3次
错因:在加点的时候堆的操作错误。
题解:
为什么有时候说点分治是一种数据结构呢?我觉得是因为点分治的核心是在分治过程中产生的树形结构,即点分树,它的深度是 \(\log\) 级别的。
对于这道题,我们首先要建立出来点分树(只记father),每个点维护所有孩子的答案。当修改时,我们暴力跳点分树上的father(仍是 \(\log\) 级别的)。
如何维护信息呢?我们开三种堆:一个堆维护自己子树中的路径长度dis,就是正常点分治中的链长;再用一个堆维护每个孩子dis的堆顶,记为ch,显然,经过这个点的最长路径为堆顶和次堆顶(最大和次大);再用一个堆记录一个全局答案。
删点时(设为 \(u\) ),我们先把之前的答案从全局堆中去掉,然后删掉路径长度为0的点,再尝试将答案加回全局堆。然后跳father,在堆中删掉对应的距离 \(len(u,x)\) 。
代码:
#include<bits/stdc++.h>
#define R register int
using namespace std;
namespace Luitaryi {
template<class I> inline I g(I& x) { x=0; register I f=1;
register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x*=f;
} const int N=100010,M=500010,Inf=0x3f3f3f3f;
int n,m,cnt,sum,rt; bool vis[N];
int vr[N<<1],nxt[N<<1],fir[N],sz[N],mx[N],d[N],c[N],fa[N],len[20][N];
inline void add(int u,int v) {
vr[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt;
vr[++cnt]=u,nxt[cnt]=fir[v],fir[v]=cnt;
}
struct heap {
priority_queue<int> dat,dst;
inline void ins(int x) {dat.push(x);}
inline void del(int x) {dst.push(x);}
inline int top() {
while(dst.size()&&dat.top()==dst.top()) dat.pop(),dst.pop();
return dat.top();
}
inline void pop() {
while(dst.size()&&dat.top()==dst.top()) dat.pop(),dst.pop(); dat.pop();
}
inline int rtop() {
R t=top(),ret; pop();
ret=top(); dat.push(t); return ret;
}
inline int size() {return dat.size()-dst.size();}
}dis[N],ch[N],ans;
inline void getsz(int u,int fa) {
sz[u]=1,mx[u]=0;
for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
if(v==fa||vis[v]) continue;
getsz(v,u),sz[u]+=sz[v];
mx[u]=max(mx[u],sz[v]);
} mx[u]=max(mx[u],sum-sz[u]);
if(mx[u]<mx[rt]) rt=u;
}
inline void dfs(int u,int fa,int s,heap& q) {
q.ins(s); for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
if(v==fa||vis[v]) continue; dfs(v,u,s+1,q);
}
}
inline void pre(int u) { vis[u]=true;
for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
if(vis[v]) continue;
sum=sz[v],rt=0,mx[0]=Inf;
getsz(v,-1),getsz(rt,-1); fa[rt]=u;
dfs(v,-1,1,dis[rt]); ch[u].ins(dis[rt].top());
d[rt]=d[u]+1; pre(rt);
} ch[u].ins(0); if(ch[u].size()>=2) ans.ins(ch[u].top()+ch[u].rtop());
else if(ch[u].size()) ans.ins(ch[u].top());
}
namespace lca {
int d[N],lg[N],f[20][N];
inline void dfs(int u,int fa) {
for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
if(v==fa) continue;
d[v]=d[u]+1; f[0][v]=u; dfs(v,u);
}
}
inline void init() {
dfs(1,-1); for(R i=2;i<=n;++i) lg[i]=lg[i>>1]+1;
for(R i=1;i<=lg[n];++i) for(R j=1;j<=n;++j)
f[i][j]=f[i-1][f[i-1][j]];
}
inline int query(int u,int v) { if(d[u]<d[v]) swap(u,v);
for(R k=lg[d[u]];~k;--k) if(d[f[k][u]]>=d[v]) u=f[k][u];
if(u==v) return u;
for(R k=lg[d[u]];~k;--k) if(f[k][u]!=f[k][v]) u=f[k][u],v=f[k][v];
return f[0][u];
}
inline int dis(int u,int v) {return d[u]+d[v]-2*d[query(u,v)];}
}
inline void main() {
g(n); for(R i=1,u,v;i<n;++i) g(u),g(v),add(u,v);
lca::init(); rt=0; mx[rt]=Inf; sum=n; getsz(1,-1),getsz(rt,-1),pre(rt);
for(R u=1;u<=n;++u) for(R i=u;i;i=fa[i]) len[d[u]-d[i]][u]=lca::dis(u,i);
g(m); while(m--) { register char s[2]; scanf("%s",s);
if(s[0]=='G') if(ans.size()) printf("%d\n",ans.top()); else puts("-1");
else { R u; g(u);
if(!c[u]) {
if(ch[u].size()>=2) ans.del(ch[u].top()+ch[u].rtop());
ch[u].del(0); if(ch[u].size()>=2) ans.ins(ch[u].top()+ch[u].rtop());
for(R i=u;fa[i];i=fa[i]) {
if(ch[fa[i]].size()>=2) ans.del(ch[fa[i]].top()+ch[fa[i]].rtop());
ch[fa[i]].del(dis[i].top());
dis[i].del(len[d[u]-d[fa[i]]][u]);
if(dis[i].size()) ch[fa[i]].ins(dis[i].top());
if(ch[fa[i]].size()>=2) ans.ins(ch[fa[i]].top()+ch[fa[i]].rtop());
}
} else {
if(ch[u].size()>=2) ans.del(ch[u].top()+ch[u].rtop());
ch[u].ins(0); if(ch[u].size()>=2) ans.ins(ch[u].top()+ch[u].rtop());
for(R i=u;fa[i];i=fa[i]) {
if(ch[fa[i]].size()>=2) ans.del(ch[fa[i]].top()+ch[fa[i]].rtop());
if(dis[i].size()) ch[fa[i]].del(dis[i].top());
dis[i].ins(len[d[u]-d[fa[i]]][u]);
ch[fa[i]].ins(dis[i].top());
if(ch[fa[i]].size()>=2) ans.ins(ch[fa[i]].top()+ch[fa[i]].rtop());
}
} c[u]^=1;
}
}
}
} signed main() {Luitaryi::main(); return 0;}
2019.08.31
69