CF161D Distance in Tree 点分治

题目:

  输入点数为N一棵树,求树上长度恰好为K的路径个数

 

分析:

  题目的数据范围不是很紧,点分治也可以过,树形dp也可以过。这里采用点分治做法。

  我们只需要单开一个类似于桶的数组,跑点分治套路,统计即可,每次处理一棵子树,先在桶上跑统计,处理完一棵子树再更新桶。这样可以保证每一段路径都直接跨过根节点内。

  记得开long long。

代码:

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 const int N=100005,M=505;
 5 struct node{int y,nxt;}e[N*2];
 6 int d[N],rt,vis[N],siz[N],c=1,q[N];
 7 int h[N],n,m,k,mx[N],sm;ll t[M],ans=0;
 8 void add(int x,int y){
 9     e[++c]=(node){y,h[x]};h[x]=c;
10 } void getrt(int x,int fa){
11     siz[x]=1;mx[x]=0;
12     for(int i=h[x],y;i;i=e[i].nxt)
13     if((y=e[i].y)!=fa&&!vis[y])
14     getrt(y,x),siz[x]+=siz[y],
15     mx[x]=max(mx[x],siz[y]);
16     mx[x]=max(mx[x],sm-siz[x]);
17     if(mx[x]<mx[rt]) rt=x;return ;
18 } void dfs(int x,int fa){
19     q[++q[0]]=d[x];
20     for(int i=h[x],y;i;i=e[i].nxt)
21     if((y=e[i].y)!=fa&&!vis[y])
22     d[y]=d[x]+1,dfs(y,x);return ;
23 } void calc(int x){
24     for(int i=h[x],y;i;i=e[i].nxt)
25     if(!vis[y=e[i].y]){
26         q[0]=0;d[y]=1;dfs(y,x);
27         for(int j=q[0];j;j--)
28         if(q[j]<=k) ans+=t[k-q[j]];
29         for(int j=q[0];j;j--)
30         if(q[j]<=k) t[q[j]]++;
31     } memset(t,0,sizeof(t));
32 } void solve(int x){
33     vis[x]=1;t[0]=1;calc(x);
34     for(int i=h[x],y;i;i=e[i].nxt)
35     if(!vis[y=e[i].y]){
36         sm=siz[y];mx[rt=0]=N;
37         getrt(y,0);solve(rt);
38     } return ;
39 } int main(){
40     scanf("%d%d",&n,&k);
41     for(int i=1,x,y;i<n;i++)
42     scanf("%d%d",&x,&y),add(x,y),add(y,x);
43     mx[rt]=sm=n;getrt(1,0);solve(rt);
44     printf("%lld
",ans);return 0;
45 }
点分治
原文地址:https://www.cnblogs.com/Alan-Luo/p/10423998.html