[codeforces161D]Distance in Tree(点分治/树形dp)

题意:求树上距离为k的点对个数;

解题关键:练习一下点分治不用容斥 而直接做的做法。注意先查询,后更新。

不过这个方法有个缺陷,每次以一个新节点为根,必须memset mp数组,或许使用map会好些,更新序号一类用ca这种形式更好些。

试了一下,map更慢,应该是带log的原因。

点分治解法:

  1 #pragma comment(linker,"/STACK:102400000,102400000")
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<cstdlib>
  6 #include<iostream>
  7 #include<cmath>
  8 #include<map>
  9 #define maxn 100040
 10 #define maxm 1000500
 11 using namespace std;
 12 typedef long long ll;
 13 const ll mod=1000003;
 14 const ll inf=1ll<<60;
 15 ll n,k,ans,size,s[maxn],f[maxn],path[maxn],cr;
 16 ll head[maxn],cnt,root;
 17 bool vis[maxn];
 18 struct edge{
 19     ll to,nxt;
 20 }e[maxn<<1];
 21 map<int,int>mp;
 22 void add_edge(ll u,ll v){
 23     e[cnt].to=v;
 24     e[cnt].nxt=head[u];
 25     head[u]=cnt++;
 26 }
 27 
 28 inline ll read(){
 29     char k=0;char ls;ls=getchar();for(;ls<'0'||ls>'9';k=ls,ls=getchar());
 30     ll x=0;for(;ls>='0'&&ls<='9';ls=getchar())x=(x<<3)+(x<<1)+ls-'0';
 31     if(k=='-')x=0-x;return x;
 32 }
 33 
 34 void get_root(ll u,ll fa){//get_root会用到size
 35     s[u]=1;f[u]=0;//f是dp数组
 36     for(ll i=head[u];i!=-1;i=e[i].nxt){
 37         ll v=e[i].to;
 38         if(v==fa||vis[v]) continue;
 39         get_root(v,u);
 40         s[u]+=s[v];
 41         f[u]=max(f[u],s[v]);
 42     }
 43     f[u]=max(f[u],size-s[u]);
 44     root=f[root]>f[u]?u:root;
 45 }
 46 
 47 void get_path_size(ll u,ll fa,ll dis){
 48     if(dis+1<=k){
 49         path[cr]=dis+1;
 50         cr++;
 51     }
 52     s[u]=1;
 53     for(ll i=head[u];i!=-1;i=e[i].nxt){
 54         ll v=e[i].to;
 55         if(v==fa||vis[v]) continue;
 56         get_path_size(v,u,dis+1);
 57         s[u]+=s[v];
 58     }
 59 }
 60 
 61 void work(ll u,ll fa){
 62     vis[u]=true;
 63     mp.clear();
 64     mp[0]=1;
 65     for(ll i=head[u];i!=-1;i=e[i].nxt){
 66         ll v=e[i].to;
 67         if(v==fa||vis[v]) continue;
 68         cr=0;
 69         get_path_size(v,u,0);
 70         for(ll j=0;j<cr;j++){
 71             ans+=mp[k-path[j]];
 72         }
 73         for(int j=0;j<cr;j++){
 74             mp[path[j]]++;
 75         }
 76     }
 77     for(ll i=head[u];i!=-1;i=e[i].nxt){
 78         ll v=e[i].to;
 79         if(vis[v]||v==fa) continue;
 80         size=s[v],root=0;
 81         get_root(v,u);
 82         work(root,u);
 83     }
 84 }
 85 
 86 void init(){
 87     memset(vis,0,sizeof vis);
 88     memset(head,-1,sizeof head);
 89     ans=cnt=0;
 90 }
 91 
 92 int main(){
 93     ll a,b;
 94     f[0]=inf;
 95     while(scanf("%I64d%I64d",&n,&k)!=EOF){
 96         init();
 97         for(int i=0;i<n-1;i++){
 98             a=read(),b=read();
 99             add_edge(a,b);
100             add_edge(b,a);
101         }
102         size=n,root=0;
103         get_root(1,-1);
104         work(root,-1);
105         printf("%d
",ans);
106     }
107     return 0;
108 }

 树形dp解法:

复杂度:$O(nk)$

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 #define maxn 100006
 5 int head[maxn],cnt,dp[maxn][502];
 6 struct edge{
 7     int to,w,nxt;
 8 }e[maxn<<1];
 9 ll ans;
10 int n,k,a,b;
11 void add_edge(int u,int v){
12     e[cnt].to=v;
13     e[cnt].nxt=head[u];
14     head[u]=cnt++;
15 }
16 
17 void dfs(int u,int fa){
18     dp[u][0]=1;
19     for(int i=head[u];i!=-1;i=e[i].nxt){
20         int v=e[i].to;
21         if(v==fa) continue;
22         dfs(v,u);
23         for(int j=1;j<=k;j++){
24             dp[u][j]+=dp[v][j-1];
25         }
26     }
27     ans+=dp[u][k];
28     int tmp=0;
29     for(int i=head[u];i!=-1;i=e[i].nxt){
30         int v=e[i].to;
31         if(v==fa) continue;
32         for(int j=1;j<k;j++){
33             tmp+=1ll*dp[v][j-1]*(dp[u][k-j]-dp[v][k-j-1]);
34         }
35     }
36     ans+=tmp/2;
37 }
38 
39 void init(){
40     memset(head,-1,sizeof head);
41     cnt=0;
42     ans=0;
43 }
44 
45 int main(){
46     init();
47     cin>>n>>k;
48     for(int i=0;i<n-1;i++){
49         cin>>a>>b;
50         add_edge(a,b);
51         add_edge(b,a);
52     }
53     dfs(1,-1);
54     cout<<ans<<"
";
55     return 0;
56 }
原文地址:https://www.cnblogs.com/elpsycongroo/p/7497013.html