zoukankan      html  css  js  c++  java
  • [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 }
  • 相关阅读:
    在Python中使用多进程快速处理数据
    深度学习中Embedding层有什么用?
    split("\s+") 和 split(" +") 有什么区别?
    python merge、concat合并数据集
    机器学习中常见的损失函数
    XGBoost、LightGBM的详细对比介绍
    $(function(){})的执行过程分析
    jQuery.extend({...})分析
    jquery核心功能分析
    print打印网页相关
  • 原文地址:https://www.cnblogs.com/elpsycongroo/p/7497013.html
Copyright © 2011-2022 走看看