• Codeforces 161D Distance in Tree(树的点分治)


    题目大概是,给一棵树,统计距离为k的点对数。

    不会DP啊。。点分治的思路比较直观,啪啪啪敲完然后AC了。具体来说是这样的:

    • 树上任何两点的路径都可以看成是一条过某棵子树根的路径,即任何一条路径都可以由一个子树到达根的一条或两条路径组成
    • 就可以分治累加各个结点为根的子树的统计数目
    • 对于各个子树可以这样统计:假设这个子树的根有a、b、c...若干个孩子,开一个数组cnt[i]记录有几个结点到根结点为i,依次处理a、b、c...结点及各自以下的结点,处理的时候根据当前的cnt数组统计数目,处理完后把新的数目更新到cnt数组。这样直接就能不重复地统计数目了
    • 时间复杂度O(nlogn)
     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 #define INF (1<<30)
     6 #define MAXN 55555
     7 struct Edge{
     8     int v,next;
     9 }edge[MAXN<<1];
    10 int NE,head[MAXN];
    11 void addEdge(int u,int v){
    12     edge[NE].v=v; edge[NE].next=head[u];
    13     head[u]=NE++;
    14 }
    15 bool vis[MAXN];
    16 int size[MAXN];
    17 void getSize(int u,int fa){
    18     size[u]=1;
    19     for(int i=head[u]; i!=-1; i=edge[i].next){
    20         int v=edge[i].v;
    21         if(v==fa || vis[v]) continue;
    22         getSize(v,u);
    23         size[u]+=size[v];
    24     }
    25 }
    26 int cen,mini;
    27 void getCentre(int u,int fa,int &tot){
    28     int res=tot-size[u];
    29     for(int i=head[u]; i!=-1; i=edge[i].next){
    30         int v=edge[i].v;
    31         if(v==fa || vis[v]) continue;
    32         getCentre(v,u,tot);
    33         res=max(res,size[v]);
    34     }
    35     if(res<mini){
    36         mini=res;
    37         cen=u;
    38     }
    39 }
    40 int getCentre(int u){
    41     mini=INF;
    42     getSize(u,u);
    43     getCentre(u,u,size[u]);
    44     return cen;
    45 }
    46 int n,k,cnt[555],tmp[555],ans;
    47 void dfs(int u,int fa,int dist){
    48     if(dist>k) return;
    49     ans+=cnt[k-dist];
    50     ++tmp[dist];
    51     for(int i=head[u]; i!=-1; i=edge[i].next){
    52         int v=edge[i].v;
    53         if(v==fa || vis[v]) continue;
    54         dfs(v,u,dist+1);
    55     }
    56 }
    57 void conquer(int u){
    58     memset(cnt,0,sizeof(cnt));
    59     cnt[0]=1;
    60     for(int i=head[u]; i!=-1; i=edge[i].next){
    61         int v=edge[i].v;
    62         if(vis[v]) continue;
    63         memset(tmp,0,sizeof(tmp));
    64         dfs(v,v,1);
    65         for(int i=1; i<=k; ++i) cnt[i]+=tmp[i];
    66     }
    67 }
    68 void divide(int u){
    69     u=getCentre(u);
    70     vis[u]=1;
    71     conquer(u);
    72     for(int i=head[u]; i!=-1; i=edge[i].next){
    73         int v=edge[i].v;
    74         if(vis[v]) continue;
    75         divide(v);
    76     }
    77 }
    78 int main(){
    79     memset(head,-1,sizeof(head));
    80     int a,b;
    81     scanf("%d%d",&n,&k);
    82     for(int i=1; i<n; ++i){
    83         scanf("%d%d",&a,&b);
    84         addEdge(a,b);
    85         addEdge(b,a);
    86     }
    87     divide(1);
    88     printf("%d",ans);
    89     return 0;
    90 }
  • 相关阅读:
    家庭内网向导帮助文档
    Nginx 容器连接 php rc-fpm 容器编译 php
    samba 容器实现共享
    编程思想(POP,OOP,SOA,AOP)
    OOP(面向对象编程)
    MySql5.6 Window超详细安装教程
    JAVA设计模式:状态模式
    Mysql设置创建时间字段和更新时间字段自动获取时间,填充时间
    eclipse里新建work set,将项目分组放在不同文件夹
    错误记录
  • 原文地址:https://www.cnblogs.com/WABoss/p/5303728.html
Copyright © 2020-2023  润新知