2020 CCPC 秦皇岛 K. Kingdom‘s Power(树形DP)
传送门
题目大意
给出一棵根节点为111的树,其中树根上面有无穷的士兵,每分钟我们能调取一队士兵走一条边,如果该节点没有被占领那么会占领该节点,问占领所有节点需要的最少时间。
解题思路
首先要能简单证明如下几个关键想法:
对于某节点uuu,它要么被其兄弟子树上的士兵折返回来占领,要么就从根节点下来一队新的士兵占领。
一队士兵到达节点uuu的子节点vvv后一定会继续向下走,要么停在叶子节点上,要么等到uuu的整个子树遍历完成后可能前往uuu的兄弟节点。
对于每个节点来说,从根节点下来的士兵的路径长度是唯一的,但是其兄弟子树的士兵往返的路径是变化的,如何最小化折返的路径长度?考虑一个节点占领一棵子树时,最优的做法是除了最长链只走一次外,其他链都会走两次。这启发我们对每个节点按最长链的长度从小到大排序,这样再进行DP的结果是最优的。
如果我们要用到第iii次操作的那队士兵,那么一定只会在i+1i+1i+1次操作时可能用到它,因为如果其兄弟节点都不会用到,那么在i+x(x>1)i+x(x>1)i+x(x>1)次操作回溯到了距离根更近的父亲节点时更不会用到。
有了以上的思路后,显然我们只需要记录上一次走到叶子节点的那队士兵,然后比较上队士兵到当前节点的距离和当前节点的深度来确定是否新派士兵。一开始一直纠结如何从上次的叶子结点转移到当前的叶子节点,写了几次发现很难维护(对于蒟蒻来说)。然后突然发现每次不管如何,都只能是一队士兵在走,我们可以不单单考虑叶子节点,而是对每个节点来看,求出要用到的士兵走到该节点需要的距离,不断更新维护当前的士兵的位置,这样本题就迎刃而解了!
附上测试的图,答案为131313:
//
// Created by Happig on 2021/3/3.
//
#include <bits/stdc++.h>
#include <unordered_map>using namespace std;
#define ENDL "\n"
#define lowbit(x) (x & (-x))
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<double, double> pdd;
const double eps = 1e-8;
const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
const double dinf = 1e300;
const ll INF = 1e18;
const int Mod = 1e9 + 7;
const int maxn = 1e6 + 10;ll ans = 0;
vector<int> G[maxn];
int maxd[maxn], d[maxn];
int pre;bool cmp(int &p, int &q) {return maxd[p] < maxd[q];
}void dfs1(int u, int deep) {d[u] = maxd[u] = deep;for (auto v:G[u]) {dfs1(v, deep + 1);maxd[u] = max(maxd[u], maxd[v]);}sort(G[u].begin(), G[u].end(), cmp);
}void dfs2(int u, int fa) {if (u != 1) {if (!pre) ans += d[u];else {if (d[pre] - d[fa] + 1 <= d[u]) ans += d[pre] - d[fa] + 1;else ans += d[u];}pre = u;}for (auto v:G[u]) {dfs2(v, u);}
}int main() {//freopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);//ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);int t, n, kase = 0;scanf("%d", &t);while (t--) {scanf("%d", &n);for (int i = 1; i <= n; i++) G[i].clear();for (int i = 2, u; i <= n; i++) {scanf("%d", &u);G[u].push_back(i);}dfs1(1, 0);ans = pre = 0;dfs2(1, 0);printf("Case #%d: %lld\n", ++kase, ans);}return 0;
}
2020 CCPC 秦皇岛 K. Kingdom‘s Power(树形DP)相关推荐
- 2020CCPC(秦皇岛) - Kingdom‘s Power(树形dp+贪心)
题目大意:给出一棵 n 个节点的有根树,点 1 为根节点,现在在根节点有无穷多个士兵,每一秒可以控制任意一个士兵向任意一个单位移动一步,士兵移动到的点会被永久占领,现在问最少需要经过多少秒,才能将所有 ...
- 2019 CCPC秦皇岛 K.MUV LUV UNLIMITED(博弈)
2019CCPC秦皇岛K 题意: 两个人玩游戏, 有一棵有根树,每次只能拿叶子节点若干个(不能不拿),问最后谁会赢 思路: 先说结论,数每个叶子节点对应上去的那条链(直到他的父亲除自己外有另外的儿子结 ...
- 2020 CCPC 秦皇岛 H.Holy Sequence
我搬运我自己应该算原创吧 题目 题意 题解 题意 对于一个长度为nnn的正整数数列ana_nan, 他合法的条件是: ∀i∈[1,n],ai∈1,2,-,n\forall i \in [1, n], ...
- 2020 CCPC 长春 K. Ragdoll(预处理+启发式合并)
LINK 考虑x⊕y=gcd(x,y)x\oplus y=gcd(x,y)x⊕y=gcd(x,y)的情况应该是非常少的 不妨设x>yx>yx>y 由于x⊕y>=x−y>= ...
- 树形dp瞎讲+树形dp基础题题解
---恢复内容开始--- 没错 咕了这么久(没有青青姐久 我又开始写博客了( ´▽`) 想了很久些什么(才没有想过呢 虽然被鄙视基础不好但还是走上了树形dp的不归路 那么 就来写写树形dp吧(dtx ...
- Codeforces 835 F Roads in the Kingdom(树形dp)
F. Roads in the Kingdom(树形dp) 题意: 给一张n个点n条边的无向带权图 定义不便利度为所有点对最短距离中的最大值 求出删一条边之后,保证图还连通时不便利度的最小值 $n & ...
- 2020 ccpc 吉林省赛 H
2020 ccpc 吉林省赛 H 题意: 给一组数 a i a_i ai,求 ∑ i = 1 n ∑ j = 1 n [ g c d ( a i , a j ) = d ] \sum\limits_ ...
- 2020 CCPC 绵阳站 J-Joy of Handcraft (调和级数 线段树)
2020 CCPC 绵阳站 J-Joy of Handcraft (调和级数 线段树) 之前一直对线段树有种恐惧感,感觉十分晦涩难懂,但是我还是得迎男而上!这题必须补!我说的!耶稣都留不住! 题目 h ...
- COCI 2020/2021 Svjetlo(树形DP)
COCI 2020/2021 Svjetlo 题目大意 求最短的树上路径(可以重复经过点或边)长度使得经过每个点的次数满足给定的奇偶性.树的大小为NNN. N≤500000N\le 500000N≤5 ...
最新文章
- Nested Mappings
- PyCharm 查找文件名
- python是一种语言吗-Python是一种什么样的编程语言?解释?编译?汇编?机械?...
- 【推荐系统】面向科研的推荐系统Benchmark诞生!
- 使用Cloud Studio写python
- 验证occ和vtk整合工作的demo
- electron-vue解决打包错误、无法调用出开发者工具(亲测有效)
- jQuery学习笔记开篇
- 计算机设计类有哪些专业,2021新高考模式下报考,这4类专业有“潜规则”,考生报考需谨慎...
- jbox弹窗_关于使用 jBox 对话框的提交不能弹出问题解决方法
- 内网地址映射为外网地址方法
- OMF(Oracle Managed Files,Oracle管理的文件)介绍
- Vue开发版本与生产版本的区别
- 【软件工程】软件工程知识点提纲8
- GCD编程认真学习(1)为什么要用GCD?
- threejs:流光效果封装
- Vmware安装Ubuntu Kylin麒麟系统图文
- 数字信号处理基于计算机的方法答案,数字信号处理—基于计算机的方法第4章答案.pdf...
- 都有哪些数据恢复软件是免费的?
- Android自动手绘,圆你儿时画家梦!