首页 > 其他分享 >洛谷 P3523 题解

洛谷 P3523 题解

时间:2024-10-06 12:21:57浏览次数:1  
标签:std infty cnt 洛谷 int 题解 max P3523 节点

洛谷 P3523 [POI2011] DYN-Dynamite

分析

二分答案,问题转化为:对于给定的 \(K\),选择尽可能少的节点,使得所有关键节点都被「覆盖」。

对于一个关键节点,「覆盖」的定义为:存在一个被选择的点与这个关键节点的距离不大于 \(K\)。

方便起见,我们指定 \(1\) 号节点是这棵树的根节点。

我们使用树形 DP 的思路,自底而上、无后效性地求解。换句话说,显然地,当我们考虑一个节点 \(u\) 时,默认 \(u\) 的子树内已经达到最优。

对于每个节点 \(u\),我们维护两个信息:

  • \(f _ u\):\(u\) 的子树内离 \(u\) 最远的 未被覆盖的关键节点 和 \(u\) 之间的距离。特别地,若 \(u\) 的子树内不存在 未被覆盖的关键节点,则 \(f _ u = -\infty\)。

  • \(g _ u\):\(u\) 的子树内离 \(u\) 最近的 被选择的节点 和 \(u\) 之间的距离。特别地,若 \(u\) 的子树内不存在 被选择的节点,则 \(g _ u = \infty\)。

初始化 \(f _ u = - \infty, g _ u = \infty\),然后从 \(u\) 的儿子节点转移:

\[f _ u = \max _ {v \in \operatorname{son}(u)} \{ f _ v + 1 \}, \\ g _ u = \max _ {v \in \operatorname{son}(u)} \{ g _ v + 1 \}. \]

现在我们对儿子节点的信息进行汇总:

  • 若 \(f _ u + g _ u \le K\),那么 \(u\) 的子树内所有关键节点都被覆盖了,更新 \(f _ u \gets -\infty\)。
  • 若 \(d _ u = 1\),\(u\) 本身是一个关键节点,更新 \(f _ u \gets \max \{f _ u, 0\}\)。

接下来决策要不要选择 \(u\),我们有贪心结论:当且仅当 \(f _ u = K\) 时选择 \(u\)。

略证:必要性显然;充分及最优性则是因为若 \(f _ u < K\) 我们就可以选择 \(u\) 的祖先,而 \(u\) 的祖先一定不比 \(u\) 劣,因为 \(u\) 的祖先可以覆盖更大的范围。

当然 $u = 1 $ 是个例外,根节点没有祖先,所以若 \(f _ 1 \ne -\infty\) 就一定要选 \(1\) 号节点。

如果选择了 \(u\),那么同样也要更新:

\[f _ u \gets -\infty, \\ g _ u \gets 0. \]

总结一下:在 \([0, n]\) 内二分 \(K\),每次判定时自底而上维护、决策,记录选择了几个点。

复杂度分析

二分复杂度为 \(\operatorname{O}(\log n)\),每次树形 DP 判定复杂度为 \(\operatorname{O}(n)\),总时间复杂度为 \(\operatorname{O}(n \log n)\)。

实现

递归常数略大,可能需要卡常。

#include <iostream>
#include <vector>

const int N = 300'000, INF = 1e9;

int n, m, cnt;
bool d[N + 5];
int f[N + 5], g[N + 5];
std::vector<int> edge[N + 5];

void dfs(int u, int fa, int k)
{
    f[u] = -INF;
    g[u] = INF;
    for (auto v : edge[u])
        if (v != fa)
        {
            dfs(v, u, k);
            f[u] = std::max(f[u], f[v] + 1);
            g[u] = std::min(g[u], g[v] + 1);
        }
    if (f[u] + g[u] <= k)
        f[u] = -INF;
    if (d[u] && g[u] > k)
        f[u] = std::max(f[u], 0);
    if (f[u] == k)
    {
        f[u] = -INF;
        g[u] = 0;
        cnt++;
    }
}

bool check(int k)
{
    cnt = 0;
    dfs(1, 0, k);
    if (f[1] >= 0)
        cnt++;
    return cnt <= m;
}

int binary_search()
{
    int l = 0, r = n, res = 0;
    while (l <= r)
    {
        int mid = (l + r) / 2;
        if (check(mid))
        {
            r = mid - 1;
            res = mid;
        }
        else
            l = mid + 1;
    }
    return res;
}

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);

    std::cin >> n >> m;
    for (int i = 1; i <= n; i++)
        std::cin >> d[i];
    for (int i = 1; i < n; i++)
    {
        int u, v;
        std::cin >> u >> v;
        edge[u].push_back(v);
        edge[v].push_back(u);
    }

    std::cout << binary_search() << "\n";

    return 0;
}

标签:std,infty,cnt,洛谷,int,题解,max,P3523,节点
From: https://www.cnblogs.com/lzy20091001/p/18448977/Luogu_P3523_solution

相关文章

  • [题解]ABC374 A~E
    A-Takahashisan2直接判断字符串是否以san结尾即可。点击查看代码#include<bits/stdc++.h>usingnamespacestd;intmain(){ strings; cin>>s; intn=s.size(); if(s[n-1]=='n'&&s[n-2]=='a'&&s[n-3]=='s')cout<<&......
  • 20241006每日一题洛谷P1031
    对题目第一印象:贪心吧,或者纯模拟第一次贪心,由于左右端堆只能想内一堆移动,遂放弃第一次模拟,开多个数组,(可能还要用递归?),遂放弃于是求助如来佛祖:从逻辑上可以看出,第一堆缺或者多的牌只能移动到第二堆上当第一堆达到期望值时,第一堆便不能再做操作,于是,可以将第二堆作为第一堆来处理......
  • P11059 [入门赛 #27] 数字 (Hard Ver.)题解
    Solution先读题:在给定x的位数\(n\)和模数\(p\)后,要求构造一个\(x\)在满足\(x\modp\)的余数尽可能小的前提下使\(x\)的数字尽可能小。我们假设\(x\)的各位数字之和为\(m\),有\(1\lem\le9n\)。.(当\(x\)仅在最高位有1时\(m=1\),称为情况一,当x每位为9时\(m=9n\),称为情况二......
  • 20241002每日一题洛谷P1563
    粗看题目我靠,什么方向还变来变去的(哭泣核心思想:圈内右数,圈外左数为整体逆时针数;圈外右数,圈内左数为整体顺时针数运用结构体就有了第一版源码:structpeople{ intface; charname[12];};intmain(){ intm,n; scanf("%d%d",&n,&m); peoplea[10010]; for(inti......
  • ABC374E 题解
    好题。爱做。标签:二分。求最大的最小值,考虑二分答案。然后问题就转化成了(求\(n\)次):有两种物品,每种物品有一个代价和价值,求获得不少于给定价值所需的最小代价。下文记物品的代价为\(w\),价值为\(v\),所拿的数量为\(cnt\)。假设有两种物品\(S\)与\(T\),\(S\)物品的性价比......
  • P10678 『STA - R6』月 题解
    Solution看了别的大佬的题解,感觉都是数学证明然后用树和图做的,看不懂啊。。。萌新瑟瑟发抖用vector模拟树,然后贪心摸索做出来了。注意到要求最深叶子结点和最浅叶子结点的距离最短时的情况,那么此时根节点应该是树中度数最大的点,把树尽可能的拓宽,深度换宽度。那么同理的根节点......
  • 题解:P11008 『STA - R7』异或生成序列
    Solution序列\(p\)是\(1\)~\(n\)的排列,因此考虑搜索回溯。由\(\sumn\le2\times10^6\)得知\(O(n^2)\)会炸,深感遗憾但仍考虑剪枝。坚信深搜过百万的蒟蒻。。。原\(b\)序列为长度\(n-1\)的序列:{\(b_1,b_2,b_3\cdotsb_n-1\)}将其前面插入一个元素\(......
  • 题解:AT_abc374_d [ABC374D] Laser Marking
    看到\(n\le6\),就知道这道题又是一道搜索了。题面有点长,信息也给的有点多,但稍微分析就可以得到只需要搜索印刷线段的顺序即可。具体的,我们在深搜函数里面传\(4\)个参数,分别代表已选线段的数量,当前位置的横纵坐标,以及当前时间。为了方便,我们表示的是已经印刷完当前线段后的时间......
  • P5593 题解
    题目分析首先考虑什么样的颜色能被链覆盖。容易想到当某种颜色恰巧在一条链上会被覆盖。所以只需要判断一种颜色是否能构成链即可,链的贡献也很好计算。算法考虑链的性质:有且仅有两个端点。凭借这个性质,可以判断一种颜色是否在一条链上。在dfs中考虑各种情况。假设一个......
  • P10418 [蓝桥杯 2023 国 A] 相连的边 题解
    一个比较有趣的树形DP,情况比较多。【题目简述】给定一棵树,求三条相连的边,其边权之和最大。【思路】以X代表当前节点,S表示儿子,G表示孙子,P表示父节点。首先把树建出来,在以下图中,我们模拟二号点的DP过程,考虑以下几种情况:有一条边指向父节点时FG(FatherGrandson):一......