zoukankan      html  css  js  c++  java
  • Codeforces 337D Book of Evil:树的直径【结论】

    题目链接:http://codeforces.com/problemset/problem/337/D

    题意:

      给你一棵树,n个节点。

      如果一个节点处放着“罪恶之书”,那么它会影响周围距离不超过d的所有节点。

      然后告诉你一部分被影响的节点aff[i],共m个。

      已知有且仅有一个节点放着“罪恶之书”。

      现在问你有多少个节点可能放着“罪恶之书”。

    题解:

      如果一个节点放着“罪恶之书”,那么它到所有aff[i]的距离都不超过d。

      也就是:max(它到aff[i]的距离) <= d

      有一个关于树的直径的结论:

        从一个点出发,不重复经过节点,若要使走的路程最远,则最终到达的点一定是树的直径的某个端点。

      在这道题中就是:

        从一个点出发,若到达aff[i]的距离在所有受影响的节点中最大。

        则节点i一定是受影响的点中,两两距离最远的一对点(op,ed)中的一个。

      所以要找出在aff[i]中,两两距离最远的一对点(op,ed)。

      也就是求所有aff[i]构成的一棵树的直径:

        先随便找一个aff[i],从它开始dfs1一遍,找出最远的点即为op。

        再从op开始,dfs1一遍,找出ed。

      然后从op和ed分别做一次dfs2,给每个距离不超过d的点的cnt加1。

      最后统计一下cnt为2的点的个数,即为答案。

    AC Code:

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <string.h>
     4 #include <vector>
     5 #define MAX_N 100005
     6 
     7 using namespace std;
     8 
     9 int n,m,d;
    10 int maxd;
    11 int op,ed;
    12 int aff[MAX_N];
    13 int cnt[MAX_N];
    14 bool flag[MAX_N];
    15 vector<int> edge[MAX_N];
    16 
    17 void read()
    18 {
    19     cin>>n>>m>>d;
    20     memset(flag,false,sizeof(flag));
    21     for(int i=1;i<=m;i++)
    22     {
    23         cin>>aff[i];
    24         flag[aff[i]]=true;
    25     }
    26     int x,y;
    27     for(int i=1;i<n;i++)
    28     {
    29         cin>>x>>y;
    30         edge[x].push_back(y);
    31         edge[y].push_back(x);
    32     }
    33 }
    34 
    35 void dfs1(int now,int p,int nd,int &v)
    36 {
    37     if(nd>maxd && flag[now])
    38     {
    39         maxd=nd;
    40         v=now;
    41     }
    42     for(int i=0;i<edge[now].size();i++)
    43     {
    44         int temp=edge[now][i];
    45         if(temp!=p)
    46         {
    47             dfs1(temp,now,nd+1,v);
    48         }
    49     }
    50 }
    51 
    52 void dfs2(int now,int p,int stp)
    53 {
    54     if(stp>d) return;
    55     cnt[now]++;
    56     for(int i=0;i<edge[now].size();i++)
    57     {
    58         int temp=edge[now][i];
    59         if(temp!=p) dfs2(temp,now,stp+1);
    60     }
    61 }
    62 
    63 void work()
    64 {
    65     maxd=-1;
    66     dfs1(aff[1],-1,0,op);
    67     maxd=-1;
    68     dfs1(op,-1,0,ed);
    69     memset(cnt,0,sizeof(cnt));
    70     dfs2(op,-1,0);
    71     dfs2(ed,-1,0);
    72     int ans=0;
    73     for(int i=1;i<=n;i++)
    74     {
    75         if(cnt[i]==2) ans++;
    76     }
    77     cout<<ans<<endl;
    78 }
    79 
    80 int main()
    81 {
    82     read();
    83     work();
    84 }
  • 相关阅读:
    浅复制(Shallow Copy)与深复制(Deep Copy)
    使Web API支持二级实体操作,兼对RESTFul风格API设计的疑惑。
    ActionResult
    如何在github上fork一个项目来贡献代码以及同步原作者的修改
    实用技巧:Google 搜索打不开的解决方法
    C# 汉字转拼音
    Windows Server AppFabric的安装、配置与问题排除
    小工具,大智慧(一)                     ——notepad++
    通用软件注册功能之建立有效的软件保护机制
    Javascript MVVM模式前端框架—Knockout 2.1.0系列:目录
  • 原文地址:https://www.cnblogs.com/Leohh/p/8204873.html
Copyright © 2011-2022 走看看