zoukankan      html  css  js  c++  java
  • 【换根dp】9.22小偷

     换根都不会了

    题目大意

    给定一棵$n$个点的树和树上一撮关键点,求到所有$m$个关键点距离的最大值$dis_{max}le LIM$的点的个数。

    $n,mle 30000,LIMle 30000$


    题目分析

    考虑在求出一个点的情况下如何转移到其子节点。

    对点$u$最直接关心的状态是$mx[u]$:所有关键点到$u$的最大距离。

    对点$u$的子节点$v$来说,$u$能带给它的只是“外面的世界”——$v$子树的补集这块贡献,也就是对于$u$的除了$v$子树的$mx[u]$。

    因为$mx[u]$的值只会是"从/不从$v$转移"两个状态,那么相当于需要辅助记一个$dx[u]$:所有关键点到$u$的可重次大距离。

    这样做两遍dfs就可以实现换根的dp了。

     1 #include<bits/stdc++.h>
     2 const int maxn = 30035;
     3 const int maxm = 60035;
     4 
     5 int n,m,lim,ans,sum,p[maxn],mx[maxn],dx[maxn];
     6 int edgeTot,head[maxn],nxt[maxm],edges[maxm];
     7 bool tag[maxn];
     8 
     9 int read()
    10 {
    11     char ch = getchar();
    12     int num = 0, fl = 1;
    13     for (; !isdigit(ch); ch=getchar())
    14         if (ch=='-') fl = -1;
    15     for (; isdigit(ch); ch=getchar())
    16         num = (num<<1)+(num<<3)+ch-48;
    17     return num*fl;
    18 }
    19 void addedge(int u, int v)
    20 {
    21     edges[++edgeTot] = v, nxt[edgeTot] = head[u], head[u] = edgeTot;
    22     edges[++edgeTot] = u, nxt[edgeTot] = head[v], head[v] = edgeTot;
    23 }
    24 void dfs1(int x, int fa)
    25 {
    26     mx[x] = dx[x] = -1;
    27     if (tag[x]) mx[x] = 0;
    28     for (int i=head[x]; i!=-1; i=nxt[i])
    29     {
    30         int v = edges[i];
    31         if (v==fa) continue;
    32         dfs1(v, x);
    33         if (mx[v]!=-1&&mx[v]+1 >= mx[x]) dx[x] = mx[x], mx[x] = mx[v]+1;
    34         else if (mx[v]!=-1&&mx[v]+1 > dx[x]) dx[x] = mx[v]+1;
    35     }
    36 }
    37 void dfs2(int x, int fa)
    38 {
    39     for (int i=head[x]; i!=-1; i=nxt[i])
    40     {
    41         int v = edges[i], val = 0;
    42         if (v==fa) continue;
    43         if (mx[x]==mx[v]+1&&mx[v]!=-1) val = dx[x]+1;
    44         else val = mx[x]+1;
    45         if (val&&val >= mx[v]) dx[v] = mx[v], mx[v] = val;
    46         else if (val&&val > dx[v]) dx[v] = val;
    47         dfs2(v, x);
    48     }
    49     if (mx[x] <= lim) ++ans;
    50 }
    51 int main()
    52 {
    53     memset(head, -1, sizeof head);
    54     n = read(), m = read(), lim = read();
    55     for (int i=1; i<=m; i++) tag[read()] = true;
    56     for (int i=1; i<n; i++) addedge(read(), read());
    57     dfs1(1, 0);
    58     dfs2(1, 0);
    59     printf("%d
    ",ans);
    60     return 0;
    61 }

    END

  • 相关阅读:
    Flex 布局教程:语法篇(转载)
    【Go】【Http】Go实现Http相关知识点
    【Git】Git相关开发流程
    【Go】杂七杂八GoLang
    【Go】初识Context与Context键值对的可能情况
    jmeter-通过json提取器 提取所有数据 给下个接口使用
    C# 后台调用存储过程超时处理方法,
    IE11脚本错误-调用的对象无效-
    IE11浏览器arrt,全选反选失效无效修改方法
    如何学习计算机知识
  • 原文地址:https://www.cnblogs.com/antiquality/p/11569233.html
Copyright © 2011-2022 走看看