变量
- int rt:重心。
- int fat[x]:点 x 在点分树上的父亲。
- int sz[x]:点 x 的子树大小。
- int mx[x]:以 x 为根时最大的子树的大小。
- int vis[x]:点 x 是否已经成为过分治中心。
函数
- void findroot(int x,int fa,int S):当前连通块大小为 S,节点 x 的父亲为 fa,在 x 的子树内继续寻找当前连通块的重心。
- void divide(int x,int S):当前连通块大小为 S,其分治中心为 x,继续将其划分。
- void build(int n):建点分树,节点数为 n。
- void change(int x,int v):将节点 x 的权值增加 v。
- int ask(int x,int k):询问原树上到 x 的距离不超过 k 的节点的权值和。
代码
struct DFTree{
int rt;
int fat[N],sz[N],mx[N],vis[N];
void findroot(int x,int fa,int S){
sz[x]=1;mx[x]=0;
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(y==fa||vis[y])continue;
findroot(y,x,S);
sz[x]+=sz[y];
mx[x]=max(mx[x],sz[y]);
}
mx[x]=max(mx[x],S-sz[x]);
if(!rt||mx[x]<mx[rt])rt=x;
}
void divide(int x,int S){
vis[x]=1;int S_;
tree.make(segrt1[x]);tree.make(segrt2[x]);
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(vis[y])continue;
rt=0;S_=(sz[x]<sz[y]?S-sz[x]:sz[y]);
findroot(y,x,S_);fat[rt]=x;
divide(rt,S_);
}
}
void build(int n){
rt=0;findroot(1,0,n);divide(rt,n);
}
void change(int x,int v){
for(int y=x;y;y=fat[y]){
tree.change(segrt1[y],dist(x,y),v);
if(fat[y])
tree.change(segrt2[y],dist(x,fat[y]),v);
}
}
int ask(int x,int k){
int ans=0;
for(int y=x,z=0,d;y;y=fat[z=y]){
if(dist(x,y)>k)continue;
d=k-dist(x,y);
ans+=tree.ask(segrt1[y],0,d);
if(z)ans-=tree.ask(segrt2[z],0,d);
}
return ans;
}
}dft;