动态点分治学习笔记
动态点分治,其实就是在点分治的基础上,记录一下x在点分树中的祖先fa[x]是谁。修改的时候就沿着fa[x]一直修改到根就好了。
(点分树的定义:把点分治时每一层的重心之间连边,这就构成了一颗高度为logn的树)
这是原树:
这是点分树
例题: [ZJOI2007]捉迷藏
一句话题意:
一棵树,节点一开始全是黑色,每次可以修改一个点的颜色(黑变白,白变黑),或者询问树中最远的两个黑点的距离。
题解:
对于每个点x,我们记录它在点分树中的子节点 到 它在点分树中的父亲fa[x] 的 在原树中 距离的集合h1(两点全黑),显然对答案的贡献就是最长的两条链的和。
然而如果这两条链有重合呢???
所以我们再记录一个集合h2[x],表示它在点分树中的子节点v 的h1[v]中的最大值 的集合
显然对答案ans的贡献就是h2[x]中的最大值和次大值的和啦
那么选择什么数据结构来维护h1[],h2[],ans呢???
可以用堆啊!开两个堆,一个记录原始数据(h),一个记录已经删除的数据(del)
询问最大值时这样就好了
while(del.size()&&(h.top()==del.top())) h.pop(),del.top();
那次大值呢?这就交给读者你啦!
注意,这题极度卡常!!!
不要直接复制代码,你会T的
逃(
code:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define mst(arr,x) memset(arr,x,sizeof(arr))
const int INF = 0x7fffffff;
const int N = 100009;
const int E = 23;
int Read() {int ret=0,nag=1;char c=getchar(); while (c>'9'||c<'0') {if(c=='-') nag=-1; c=getchar();} while (c<='9'&&c>='0') ret=(ret<<3)+(ret<<1)+c-'0',c=getchar(); return ret*nag;}
void Print(int x) {if(x<0) putchar('-'),x=-x; if(x>9) Print(x/10); putchar(x%10+'0');}
int n,T,head[N],to[N<<1],nxt[N<<1],CNT,val[N],cnt,dep[N],h[N][E+2];
int siz[N],weight[N],rt,SIZ,visit[N],FA[N];
struct node
{
priority_queue <int> h,del;int siz;
void Insert(int x) {h.push(x),siz++;}
void Delete(int x) {del.push(x),siz--;}
int rk1() {while(del.size()&&(h.top()==del.top())) h.pop(),del.pop();return h.top();}
int rk2() {int t=rk1(),ret;h.pop(),ret=rk1(),h.push(t);return ret;}
}h1[N],h2[N],ans;
inline void Add_edge(int x,int y){CNT++,to[CNT]=y,nxt[CNT]=head[x],head[x]=CNT;}
inline void ins(int x){if(h2[x].siz>1) ans.Insert(h2[x].rk1()+h2[x].rk2());}
inline void del(int x){if(h2[x].siz>1) ans.Delete(h2[x].rk1()+h2[x].rk2());}
void dfs0(int x,int Fa)
{
dep[x]=dep[Fa]+1;h[x][0]=Fa;
for(int j=1;j<=E;j++) h[x][j]=h[h[x][j-1]][j-1];
for(int k=head[x];k;k=nxt[k])
{
int v=to[k];if(v==Fa) continue;
dfs0(v,x);
}
}
int lca(int x,int y)
{
if(x==y) return x;
if(dep[x]<dep[y]) swap(x,y);
for(int j=E;j>=0;j--) if(dep[h[x][j]]>=dep[y]) x=h[x][j];
if(x==y) return x;
for(int j=E;j>=0;j--) if(h[x][j]!=h[y][j]) x=h[x][j],y=h[y][j];
return h[x][0];
}
int d(int x,int y){return dep[x]+dep[y]-2*dep[lca(x,y)];}
void getroot(int x,int Fa)
{
siz[x]=1,weight[x]=0;
for(int k=head[x];k;k=nxt[k])
{
int v=to[k];if(v==Fa||visit[v]) continue;
getroot(v,x),siz[x]+=siz[v],weight[x]=max(weight[x],siz[v]);
}
weight[x]=max(weight[x],SIZ-siz[x]);
if(weight[rt]>weight[x]) rt=x;
}
void getdis(int x,int Fa,int y)
{
h1[rt].Insert(d(x,y));
for(int k=head[x];k;k=nxt[k])
{
int v=to[k];if(v==Fa||visit[v]) continue;
getdis(v,x,y);
}
}
void Build(int x,int Fa)
{
visit[x]=1,h2[x].Insert(0);
getdis(x,0,Fa);
for(int k=head[x];k;k=nxt[k])
{
int v=to[k];if(visit[v]) continue;
weight[rt=0]=INF,SIZ=siz[v],getroot(v,0);
FA[rt]=x; int t=rt;Build(rt,x);
h2[x].Insert(h1[t].rk1());
}
ins(x);
}
char opt[5];
void Modify0(int x)
{
del(x),h2[x].Delete(0),ins(x);
for(int i=x;FA[i];i=FA[i])
{
del(FA[i]);
if(h1[i].siz) h2[FA[i]].Delete(h1[i].rk1());
h1[i].Delete(d(x,FA[i]));
if(h1[i].siz) h2[FA[i]].Insert(h1[i].rk1());
ins(FA[i]);
}
}
void Modify1(int x)
{
del(x),h2[x].Insert(0),ins(x);
for(int i=x;FA[i];i=FA[i])
{
del(FA[i]);
if(h1[i].siz) h2[FA[i]].Delete(h1[i].rk1());
h1[i].Insert(d(x,FA[i]));
if(h1[i].siz) h2[FA[i]].Insert(h1[i].rk1());
ins(FA[i]);
}
}
int main ()
{
cnt=n=Read();for(int i=1;i<=n;i++) val[i]=1;
for(int i=1;i<n;i++) {int x=Read(),y=Read();Add_edge(x,y),Add_edge(y,x);}
SIZ=n,weight[rt=0]=INF;getroot(1,0),dfs0(rt,0);
Build(rt,0);
T=Read();
while(T--)
{
scanf("%s",opt);
if(opt[0]=='C')
{
int x=Read();
if(val[x]) Modify0(x),val[x]=0,cnt--;
else Modify1(x),val[x]=1,cnt++;
}
else
{
if(cnt<2) Print(cnt-1),puts("");
else Print(ans.rk1()),puts("");
}
}
return 0;
}
作者:bjxdw
-------------------------------------------
个性签名:Hello,world!
如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!