@xzyxzy
2018-08-17T11:01:39.000000Z
字数 1587
阅读 1868
数据结构
鉴于没有人会看我的博客学习点分治,所以就不详细解说算法了,提供一个板子逼着自己背下来
板子:[luogu3806]【模板】点分治1
求树上是否存在距离为的路径,多组询问
点分治支持以下函数
Getroot Getdis Calc solve
void Getroot(int x,int fa){siz[x]=1;mx[x]=0;for(int i=head[x];~i;i=a[i].next){int R=a[i].to;if(R==fa||vis[R]) continue;Getroot(R,x);siz[x]+=siz[R];mx[x]=max(mx[x],siz[R]);}mx[x]=max(mx[x],sum-siz[x]);if(mx[x]<mx[root]) root=x;}
void Getdis(int x,int fa){dis[++cnt]=dep[x];for(int i=head[x];~i;i=a[i].next){int R=a[i].to;if(vis[R]||R==fa) continue;dep[R]=dep[x]+a[i].w;Getdis(R,x);}}
void Calc(int x,int d,int op){cnt=0;dep[x]=d;Getdis(x,0);sort(dis+1,dis+cnt+1);for(int i=1;i<=M;i++){int l=1,r=cnt;while(l<r)if(dis[l]+dis[r]>K[i]) r--;else{if(dis[l]+dis[r]==K[i])for(int k=r;dis[k]==dis[r]&&k>=l;k--)Yes[i]+=op;l++;}}}
void Solve(int x){Calc(x,0,1);vis[x]=1;int tt=sum;for(int i=head[x];~i;i=a[i].next){int R=a[i].to;if(vis[R]) continue;Calc(R,a[i].w,-1);sum=siz[R]>siz[x]?tt-siz[x]:siz[R];//siz要注意了————Cwenroot=0;Getroot(R,x);Solve(root);}}
int main(){root=0;mx[0]=sum=N;Getroot(1,0);Solve(root);}
在我所做过的题中,他可以用来求解树上路径问题
1.长为(小于)的路径条数(以及这条路径的最少边数)
2.长为三的倍数的路径条数
3.路径点权之积的字典序最小点对
区别在于递归时要记录上级重心,由此产生的父子关系构成点分树
于是在点分树上维护很多很多东西就可以支持动态修改了
大家看看这题-幻想乡战略游戏(动态维护带权重心)