【CF161D】Distance in Tree-树状dp

Problem Distance in tree

题目大意

给出一棵树,求这棵树上有多少个最短距离为k的点对。

Solution

这个题目可以用点分治来做,然而我到现在还是没有学会点分治,所以只好用树形dp了。

这个题目,我们可以将其转化为一个个子树中搞事情,再慢慢合并。

设f[i][j]为以i为根的子树中距离根距离为j的点有多少个。

对于一个点u,我们枚举它的子节点v,则我们可以计算出经过u-v这条边的答案

我们枚举j=1->k,则ans+=f[u][j]*f[v][k-j-1];

枚举完以后,我们将这一棵子树合并到u节点去,以便统计u的其它子树。

 

具体过程我们只需要dfs一遍,对于每个叶子结点x,f[x][0]=1。

然后不断向上回溯,边回溯边进行如上计算,最后即可算出正确答案。

具体可以参考一下代码。

AC Code

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 struct node{
 6     int to,next;
 7 }e[100010];
 8 int n,k,u,v,ans=0,tot=0;
 9 int h[50010],f[50010][510];
10 void add(int u,int v){
11     e[++tot].to=u;e[tot].next=h[v];h[v]=tot;
12     e[++tot].to=v;e[tot].next=h[u];h[u]=tot;
13 }
14 void dfs(int x,int last){
15     f[x][0]=1;
16     for(int i=h[x];~i;i=e[i].next){
17         if(e[i].to!=last){
18             dfs(e[i].to,x);
19             for(int j=0;j<k;j++)ans+=f[x][j]*f[e[i].to][k-j-1];
20             for(int j=1;j<=k;j++)f[x][j]+=f[e[i].to][j-1];
21         }
22     }
23 }
24 int main(){
25 //  freopen("cf161d.in","r",stdin);
26     memset(h,-1,sizeof(h));
27     scanf("%d%d",&n,&k);
28     for(int i=1;i<n;i++){
29         scanf("%d%d",&u,&v);
30         add(u,v);
31     }
32     dfs(1,1);
33     printf("%d",ans);
34 }

 

 

复制代码
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 struct node{
 6     int next,to;
 7 }e[200010];
 8 bool neko[100010];
 9 int n,m,d,x,u,v,path[100010],h[100010],ans=0,tot=0;
10 int pathp[100010],pathn[100010];
11 void add(int u,int v){
12     e[++tot].to=u;e[tot].next=h[v];h[v]=tot;
13     e[++tot].to=v;e[tot].next=h[u];h[u]=tot;
14 }
15 void dfspath(int x,int last){
16     path[x]=-2333333;pathp[x]=-2333333;
17     for(int i=h[x];~i;i=e[i].next){
18         if(e[i].to!=last){
19             dfspath(e[i].to,x);
20             if(path[x]<path[e[i].to]+1){
21                 pathp[x]=path[x];
22                 path[x]=path[e[i].to]+1;
23                 pathn[x]=e[i].to;
24             }else if(pathp[x]<path[e[i].to]+1)pathp[x]=path[e[i].to]+1;
25         }
26     }
27     if(neko[x]&&path[x]<-2000000)path[x]=0;
28     if(neko[x]&&pathp[x]<-2000000)pathp[x]=0;
29 }
30 void dpdfs(int x,int last){
31     if(~last)
32     if(pathn[last]==x){
33         if(pathp[last]+1>path[x]){
34             pathp[x]=path[x];
35             path[x]=pathp[last]+1;
36             pathn[x]=0;
37         }else if(pathp[last]+1>pathp[x])pathp[x]=pathp[last]+1;
38     }else{
39         if(path[last]+1>path[x]){
40             pathp[x]=path[x];
41             path[x]=path[last]+1;
42             pathn[x]=0;
43         }else if(path[last]+1>pathp[x])
44             pathp[x]=path[last]+1;
45     }
46     if(path[x]<=d)ans++;
47     for(int i=h[x];~i;i=e[i].next) 
48         if(e[i].to!=last)dpdfs(e[i].to,x);
49 }
50 int main(){
51 //  freopen("cf337d.in","r",stdin);
52     memset(h,-1,sizeof(h));
53     scanf("%d%d%d",&n,&m,&d);
54     for(int i=1;i<=m;i++)
55         scanf("%d",&x),neko[x]=1;
56     for(int i=1;i<n;i++){
57         scanf("%d%d",&u,&v);
58         add(u,v);
59     }
60     dfspath(1,1);
61     dpdfs(1,-1);
62     printf("%d",ans);
63 }
复制代码

 

 
 
标签:  树形dp
好文要顶  关注我  收藏该文   
0
0
 
 
 
« 上一篇: [CF697D]Puzzles 树形dp/期望dp
posted @  2017-07-09 16:09  skylynf 阅读( 4) 评论( 1编辑  收藏
 

 
   回复引用删除
#1楼   2017-07-09 20:02  ywwyww   
 

转载于:https://www.cnblogs.com/skylynf/p/7142686.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值