点分治学习笔记
前言
淀粉是高分子碳水化合物,是由葡萄糖分子聚合而成的。其基本构成单位为α-D-吡喃葡萄糖,分子式为(C6H10O5 )n。 -- 百度百科
淀粉质食物,主要指富含碳水化合物的食物以及根茎类蔬菜。 -- 百度知道
模板题
点分治总体思想:
设
样例分析
我们假设以
对于
我们向上回溯,由
最后得到了
这显然是树形 DP 的思想,每次求
但是我们看一下这题(模板题)
有边权的树,问有多少条长不超过
k 的路径
DP:设
这样的话,每次转移的时间是
有没有更简便的方法呢?显然是有的。我们需要让
所以我们换根为重心。
我们取出了重心,有了一些新的子树(黄色圈出来的)
这样,复杂度控制在
现在总体步骤已经确定了,对于子树
算法步骤
对于计算出
- 枚举+排序+双游标算出
k_u - 枚举儿子节点
v - 算出
v 子树的重心r - 换根为
r ,重新算到根的距离 - 分治计算
r - 用
f_v 更新f_u
- 算出
其实其他点分治也差不多是这样的,不过重新计算和求
#include<bits/stdc++.h>
using namespace std;
const int N=50009;
int n,k,ans;
struct tree{
struct edge{int to,nxt,w;}e[N*2]; int hd[N],tot;
void add(int u,int v,int w){e[++tot]=(edge){v,hd[u],w};hd[u]=tot;}
int mx[N],sz[N],d[N]; bool vst[N];
int find_root(int u,int fa,int cnt,int root){
mx[u]=0,sz[u]=1;
for(int i=hd[u],v;i;i=e[i].nxt)
if((v=e[i].to)!=fa&&!vst[v]){
root=find_root(v,u,cnt,root);
mx[u]=max(mx[u],sz[v]), sz[u]+=sz[v];
}
mx[u]=max(mx[u],cnt-sz[u]); if(mx[u]<=(cnt+1)/2.) root=u;
return root;
}
int p[N],cnt;
void update(int u,int fa){
p[++cnt]=d[u]; sz[u]=1;
for(int i=hd[u],v;i;i=e[i].nxt)
if((v=e[i].to)!=fa&&!vst[v])
d[v]=d[u]+e[i].w,update(v,u),sz[u]+=sz[v];
}
int cal(int u,int base,int ret=0){
d[u]=base,cnt=0,update(u,-1);
sort(p+1,p+cnt+1);
int l=1,r=cnt; while(l<r) p[l]+p[r]<=k? ret+=(r-(l++)):r--;
return ret;
}
void dfz(int u){
vst[u]=1; ans+=cal(u,0);
for(int i=hd[u],v;i;i=e[i].nxt)
if(!vst[(v=e[i].to)])
ans-=cal(v,e[i].w),dfz(find_root(v,u,sz[v],0));
}
}tr;
int main(){
scanf("%d",&n);
for(int i=1,u,v,w;i<n;i++)
scanf("%d%d%d",&u,&v,&w),tr.add(u,v,w),tr.add(v,u,w);
scanf("%d",&k);
tr.dfz(tr.find_root(1,-1,n,0)); printf("%d",ans);
return 0;
}