1. 程式人生 > >[CF161D]Distance in Tree-樹狀dp

[CF161D]Distance in Tree-樹狀dp

bottom colspan gnu -i author pac gin 服務 轉化

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 好文要頂 關註我 收藏該文 技術分享 技術分享 技術分享 skylynf
關註 - 0
粉絲 - 0 0 0 ? 上一篇:[CF697D]Puzzles 樹形dp/期望dp posted @ 2017-07-09 16:09 skylynf 閱讀(4) 評論(1) 編輯 收藏
評論列表 回復引用刪除 #1樓 2017-07-09 20:02 ywwyww orz 支持(0)反對(0) 刷新評論刷新頁面返回頂部 發表評論

昵稱:

評論內容: 技術分享 技術分享 技術分享 技術分享 技術分享 技術分享

退出

[Ctrl+Enter快捷鍵提交]

最新IT新聞:
· 今日頭條知乎向蘋果妥協後 微博問答也上交手續費
· Petya勒索軟件作者公開解密主密鑰
· 終於等到你!黑莓中國官方微博開通:要搞事情?
· 4K屏幕+眼球追蹤!三星秘密開發:最強VR一體機
· 熊孩子把萬元現金塞微波爐火化 支付寶神吐槽
? 更多新聞... 最新知識庫文章:
· 小printf的故事:什麽是真正的程序員?
· 程序員的工作、學習與績效
· 軟件開發為什麽很難
· 唱吧DevOps的落地,微服務CI/CD的範本技術解讀
· 程序員,如何從平庸走向理想? ? 更多知識庫文章...

公告

昵稱:skylynf
園齡:5天
粉絲:0
關註:0
< 2017年7月 >
25 26 27 28 29 30 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

搜索

常用鏈接

  • 我的隨筆
  • 我的評論
  • 我的參與
  • 最新評論
  • 我的標簽

我的標簽

  • 樹形dp(2)
  • 替罪羊樹(1)
  • 主席樹(1)
  • 左偏樹(1)
  • 期望dp(1)

隨筆檔案

  • 2017年7月 (4)
  • 2017年1月 (1)

[CF161D]Distance in Tree-樹狀dp