好吧,我想说,动态点分治思路好理解,但打起来真让人心累。
所谓动态点分治,就是点分治在线修改和查询。
此时,我们构造一个点分树,先找整棵树的重心,以他为根,将他和每个子树的重心连边,以此类推。
对于每个重心,我们维护一些需要的信息
我们在修改的时候,只需要沿着点分树往上跳修改信息就好了。
动态点分树到这里就讲完了,但真正的难点是你的维护和修改。
例题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