好吧,我想说,动态点分治思路好理解,但打起来真让人心累。
所谓动态点分治,就是点分治在线修改和查询。
此时,我们构造一个点分树,先找整棵树的重心,以他为根,将他和每个子树的重心连边,以此类推。
对于每个重心,我们维护一些需要的信息
我们在修改的时候,只需要沿着点分树往上跳修改信息就好了。
动态点分树到这里就讲完了,但真正的难点是你的维护和修改。
例题1:P2056 [ZJOI2007]捉迷藏
网址:https://www.luogu.com.cn/problem/P2056
这题被号称是最水的动态点分治,但是我看了两个小时才明白,然后又打了一个小时,呜呜。
我的代码借鉴了https://www.cnblogs.com/LadyLex/p/8006488.html
可是哪位大佬太强,两三句就说完了,我这里算是对他的补充说明吧。
找最长链,那么我们需要维护最长链和次长链,但是由于数据可以被修改,所以不能只维护这两条。
定义一个堆h2[i]用来维护以i为重心的树上的黑店到i的距离。
但是我们不可能每次修改都重新遍历整棵树重新计算h2吧,所以再定义h1[i]用于维护以i为重心的树上的黑点到i在点分树上的父亲的距离。
这样一来,h2里面只用存储它的每个子树的h1.top()了,哈哈哈。
但我们要求的是求出整棵树的最大值,那不简单,再来一个堆h3呗。
h3只用管每个h2的最大和次大之和最大就好了。
考虑到修改的时候需要删除队列里的值,那么我们给每个堆定义两个优先队列,一个负责存进的,一个负责存删的。
当要删的元素不在队首时,我们删不到他,但他也不影响结果。一旦他来到队首影响结果的时候,我们就可以删除他了。
在修改的时候,不管三七二十一,应为此次修改有可能影响到答案,所以将他的一切信息删除,即从h3中剔除h2的最长+次长,从h2中剔除h1的最长。
对这个值进行修改,然后再把h1的最长加入h2,把h2的最长+次长加入h3。
这道题到这就算讲完了,看代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=200000+100;
#define inf 1e9
inline int read(){
int x=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){
if(c=='-')f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=(x<<1)+(x<<3)+c-'0';
c=getchar();
}
return x*f;
}
inline char getc(){
char c=getchar();
while(c<'A'||c>'Z')c=getchar();
return c;
}
struct heap{
priority_queue<int>q1,q2;
inline void push(int x){q1.push(x);}
inline void erase(int x){q2.push(x);}
inline int top(){
while(q2.size()&&q1.top()==q2.top())q1.pop(),q2.pop();
return q1.top();
}
inline void pop(){
while(q2.size()&&q1.top()==q2.top())q1.pop(),q2.pop();
q1.pop();
}
inline int top2(){
int tmp=top();pop();
int ret=top();push(tmp);
return ret;
}
inline int size(){
return q1.size()-q2.size();
}
}h1[maxn],h2[maxn],h3;
int n,beg[maxn],nex[maxn],to[maxn],e;
void add(int x,int y){
e++;nex[e]=beg[x];
beg[x]=e;to[e]=y;
}
int dep[maxn],f[maxn][25];
void build(int x,int fa){
dep[x]=dep[fa]+1;
f[x][0]=fa;
for(int i=1;i<=20;i++)
f[x][i]=f[f[x][i-1]][i-1];
for(int i=beg[x];i;i=nex[i]){
int t=to[i];
if(t==fa)continue;
build(t,x);
}
}
int lca(int x,int y){
if(dep[x]<dep[y])swap(x,y);
for(int i=20;i>=0;i--)
if(dep[x]-(1<<i)>=dep[y])x=f[x][i];
if(x==y)return x;
for(int i=20;i>=0;i--)
if(f[x][i]!=f[y][i]){
x=f[x][i];
y=f[y][i];
}
return f[x][0];
}
int sz[maxn],son[maxn],vis[maxn];
int mx,rt,size;
void getrt(int x,int fa){
sz[x]=1,son[x]=0;
for(int i=beg[x];i;i=nex[i]){
int t=to[i];
if(t==fa||vis[t])continue;
getrt(t,x);
sz[x]+=sz[t];
if(son[x]<sz[t])son[x]=sz[t];
}
if(son[x]<size-sz[x])son[x]=size-sz[x];
if(son[x]<mx)mx=son[x],rt=x;
}
int las[maxn];
int dis(int a,int b){
return dep[a]+dep[b]-2*dep[lca(a,b)];
}
void stk(int x,int fa,int v){
h1[rt].push(dis(x,v));
for(int i=beg[x];i;i=nex[i]){
int t=to[i];
if(t==fa||vis[t])continue;
stk(t,x,v);
}
}
void divide(int x,int fa){
las[x]=fa;
vis[x]=1;
h2[x].push(0);
int siz=size;
for(int i=beg[x];i;i=nex[i]){
int t=to[i];
if(vis[t])continue;
if(sz[t]>sz[x])size=siz-sz[x];
else size=sz[t];
rt=0,mx=inf,getrt(t,0),stk(rt,0,x);
h2[x].push(h1[rt].top());
divide(rt,x);
}
if(h2[x].size()>1)h3.push(h2[x].top()+h2[x].top2());
}
int state[maxn],cnt,q;
void turnoff(int x){
if(h2[x].size()>1)h3.erase(h2[x].top()+h2[x].top2());
h2[x].push(0);
if(h2[x].size()>1)h3.push(h2[x].top()+h2[x].top2());
int tmp=las[x],p=x;
while(tmp){
if(h2[tmp].size()>1)h3.erase(h2[tmp].top()+h2[tmp].top2());
if(h1[p].size())h2[tmp].erase(h1[p].top());
h1[p].push(dis(x,tmp));
h2[tmp].push(h1[p].top());
if(h2[tmp].size()>1)h3.push(h2[tmp].top()+h2[tmp].top2());
p=tmp;tmp=las[tmp];
}
}
void turnon(int x){
if(h2[x].size()>1)h3.erase(h2[x].top()+h2[x].top2());
h2[x].erase(0);
if(h2[x].size()>1)h3.push(h2[x].top()+h2[x].top2());
int tmp=las[x],p=x;
while(tmp){
if(h2[tmp].size()>1)h3.erase(h2[tmp].top()+h2[tmp].top2());
h2[tmp].erase(h1[p].top());
h1[p].erase(dis(x,tmp));
if(h1[p].size())h2[tmp].push(h1[p].top());
if(h2[tmp].size()>1)h3.push(h2[tmp].top()+h2[tmp].top2());
p=tmp;tmp=las[tmp];
}
}
int main(){
n=read();
int x,y;
for(int i=1;i<n;i++){
x=read(),y=read();
add(x,y),add(y,x);
}
build(1,0);
mx=inf,rt=0,size=n;
getrt(1,0);
divide(rt,0);
cnt=n;
q=read();
while(q--){
char opt;
opt=getc();
if(opt=='C'){
int x;
x=read();
if(state[x])cnt++,turnoff(x);
else cnt--,turnon(x);
state[x]^=1;
}else{
if(cnt<2)printf("%d\n",cnt-1);
else printf("%d\n",h3.top());
}
}
return 0;
}
深深地感到自己的渺小……
来源:https://www.cnblogs.com/syzf2222/p/12289508.html