点分治模板
1.选取树的重心p
2.从p出发进行DFS,求得所需的数组
3.执行cal(p)
4.删除p结点,对p的每颗子树(无根树)递归执行1~4步
此算法在蓝书中亦有记载
vector<pii>e[maxn];
int sz[maxn];
int vis[maxn];
int dp[maxn];
int k;
int n;
int ans=0;
int root=0;
void getSz(int u,int fa){
sz[u]=1;
for(auto[v,w]:e[u]){
if(vis[v]||fa==v)continue;
getSz(v,u);
sz[u]+=sz[v];
}
}
void find(int u,int fa,int tot){
sz[u]=1;
dp[u]=0;
for(auto[v,w]:e[u]){
if(vis[v]||v==fa)continue;
find(v,u,tot);
sz[u]+=sz[v];
dp[u]=max(dp[u],sz[v]);
}
dp[u]=max(dp[u],tot-sz[u]);
if(dp[u]<dp[root])root=u;
}
void collect(int u,int fa,int dis,vector<int>&d){
d.pb(dis);
for(auto[v,w]:e[u]){
if(vis[v]||v==fa)continue;
collect(v,u,dis+w,d);
}
}
int cal(vector<int>&d){
sort(d.begin(),d.end());
int cnt=0;
int l=0,r=d.size()-1;
while(l<r){
if(d[l]+d[r]<=k){
cnt+=r-l;
l++;
}else r--;
}
return cnt;
}
void work(int u,int tot){
if(tot<=1)return;
int G=u;
find(u,-1,tot);
vis[G]=1;
vector<int>path={0};
for(auto[v,w]:e[G]){
if(vis[v])continue;
vector<int>sub;
collect(v,G,w,sub);
ans-=cal(sub);
for(auto s:sub)path.pb(s);
}
ans+=cal(path);
for(auto[v,w]:e[G]){
if(vis[v])continue;
int size=sz[v];
work(v,size);
}
}```

浙公网安备 33010602011771号