• 【换根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

  • 相关阅读:
    关于python Tk中实时的输出.
    tkinter调取签名网而设计签名页面(十七)
    多进程Multiprocessing模块
    tkinter做一个简单的登陆页面(十六)
    maven常用命令
    通用接口测试用例
    关于log4j
    场景测试-支付场景
    自动化测试的意义
    自动化测试之明确目的
  • 原文地址:https://www.cnblogs.com/antiquality/p/11569233.html
Copyright © 2020-2023  润新知