Codeforces 1120D (树形DP 或 最小生成树)
题意看这篇博客:https://blog.csdn.net/dreaming__ldx/article/details/88418543
思路看这篇:https://blog.csdn.net/corsica6/article/details/88115948
有个坑点,不能深搜去找具体方案,不然 test14 会 MLE(或许是本蒟蒻写丑了)
代码:
#include <bits/stdc++.h>
#define LL long long
#define pii pair<int, int>
using namespace std;
const int maxn = 200010;
int head[maxn], Next[maxn * 2], ver[maxn * 2], tot;
int a[maxn];
LL dp[maxn][2], sum[maxn], f[maxn];
bool v[maxn][2];
bool res[maxn];
vector<int> ans;
bool is_leaf[maxn];
void add(int x, int y) {
ver[++tot] = y;
Next[tot] = head[x];
head[x] = tot;
}
void dfs1(int x, int fa) {
int cnt = 0;
f[x] = fa;
for (int i = head[x]; i; i = Next[i]) {
int y = ver[i];
if(y == fa) continue;
dfs1(y, x);
sum[x] += dp[y][0];
cnt++;
}
if(cnt == 0) {
dp[x][0] = a[x];
dp[x][1] = 0;
is_leaf[x] = 1;
return;
}
for (int i = head[x]; i; i = Next[i]) {
int y = ver[i];
if(y == fa) continue;
dp[x][0] = min(dp[x][0], sum[x] - dp[y][0] + dp[y][1] + a[x]);
dp[x][1] = min(dp[x][1], sum[x] - dp[y][0] + dp[y][1]);
}
dp[x][0] = min(dp[x][0], sum[x]);
} void bfs() {
queue<pii> q;
q.push(make_pair(1, 0));
while(!q.empty()) {
pii tmp = q.front();
q.pop();
int x = tmp.first, flag = tmp.second;
if(v[x][flag]) continue;
v[x][flag] = 1;
if(flag == 0) {
int pos = -1, cnt = 0;
if(is_leaf[x]) {
res[x] = 1;
continue;
}
for (int i = head[x]; i; i = Next[i]) {
int y = ver[i];
if(y == f[x]) continue;
if(dp[x][flag] == sum[x] - dp[y][0] + dp[y][1] + a[x]) {
if(v[y][1]) continue;
res[x] = 1;
q.push(make_pair(y, 1));
pos = y;
cnt++;
}
}
for (int i = head[x]; i; i = Next[i]) {
int y = ver[i];
if(v[y][0]) continue;
if(y == f[x] || y == pos) continue;
q.push(make_pair(y, 0));
}
if(cnt > 1 || (sum[x] == dp[x][0] && pos != -1)) {
if(v[pos][0]) continue;
q.push(make_pair(pos, 0));
}
} else {
int pos = -1, cnt = 0;
for (int i = head[x]; i; i = Next[i]) {
int y = ver[i];
if(y == f[x]) continue;
if(dp[x][flag] == sum[x] - dp[y][0] + dp[y][1]) {
if(v[y][1]) continue;
q.push(make_pair(y, 1));
pos = y;
cnt++;
}
}
for (int i = head[x]; i; i = Next[i]) {
int y = ver[i];
if(v[y][0]) continue;
if(y == f[x] || y == pos) continue;
q.push(make_pair(y, 0));
}
if(cnt > 1) {
if(v[pos][0]) continue;
q.push(make_pair(pos, 0));
}
}
}
}
int main() {
int n, x, y;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
for (int i = 1; i < n; i++) {
scanf("%d%d", &x, &y);
add(x, y);
add(y, x);
}
memset(dp, 0x3f, sizeof(dp));
dfs1(1, -1);
bfs();
for (int i = 1; i <= n; i++) {
if(res[i])
ans.push_back(i);
}
printf("%lld %d\n", dp[1][0], ans.size());
sort(ans.begin(), ans.end());
for (int i = 0; i < ans.size(); i++)
printf("%d ", ans[i]);
printf("\n");
}
最小生成树解法先留个坑在这。。。
补坑:
思路看这篇博客:https://www.cnblogs.com/river-flows-in-you/p/10596821.html
说一下我个人的理解:把每个叶子节点看成新图的顶点,对于原树中的每个顶点,我们可以计算出它影响哪些叶子节点,用差分的思想连边。只要求出了生成树就说明可以任意取,因为形成生成树之后,我们对每个点的赋值操作就可以类比在生成树上遍历的过程。
代码:
#include <bits/stdc++.h>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 200010;
int head[maxn], Next[maxn * 2], ver[maxn * 2], tot;
int sz[maxn], cnt, l[maxn], r[maxn], a[maxn], f[maxn];
bool v[maxn];
struct Edge{
int u, v, w, id;
bool operator < (const Edge& rhs) const {
return w < rhs.w;
}
};
Edge b[maxn];
void add(int x, int y) {
ver[++tot] = y;
Next[tot] = head[x];
head[x] = tot;
}
void dfs(int x, int fa) {
sz[x] = 1;
l[x] = INF, r[x] = -1;
for (int i = head[x]; i; i = Next[i]) {
int y = ver[i];
if(y == fa) continue;
dfs(y, x);
sz[x] += sz[y];
l[x] = min(l[x], l[y]);
r[x] = max(r[x], r[y]);
}
if(sz[x] == 1) {
l[x] = r[x] = ++cnt;
}
b[x] = (Edge){l[x], r[x] + 1, a[x], x};
}
int get(int x) {
if(x == f[x]) return x;
return f[x] = get(f[x]);
}
int main() {
int n, x, y;
scanf("%d", &n);
int sum = 0;
LL ans = 0;
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
for (int i = 1; i < n; i++) {
scanf("%d%d", &x, &y);
add(x, y);
add(y, x);
}
dfs(1, -1);
sort(b + 1, b + 1 + n);
cnt++;
for (int i = 1; i <= cnt; i++) f[i] = i;
for(int L = 1, R; L <= n; L = R + 1) {
R = L;
while(b[L].w == b[R + 1].w && R < n) R++;
for (int i = L; i <= R; i++) {
x = get(b[i].u), y = get(b[i].v);
if(x != y) {
v[b[i].id] = 1;
sum++;
}
}
for (int i = L; i <= R; i++) {
x = get(b[i].u), y = get(b[i].v);
if(x != y) {
ans += b[i].w;
// printf("%lld %d\n", ans, b[i].w);
f[x] = y;
}
}
}
// printf("%lld %d\n", ans, sum);
cout << ans << " " << sum << endl;
for (int i = 1; i <= n; i++)
if(v[i]) printf("%d ", i);
}
Codeforces 1120D (树形DP 或 最小生成树)的更多相关文章
- Codeforces 1153D 树形DP
题意:有一个游戏,规则如下:每个点有一个标号,为max或min, max是指这个点的值是所有子节点中值最大的那一个,min同理.问如何给这颗树的叶子节点赋值,可以让这棵树的根节点值最大. 思路:很明显 ...
- Codeforces 1088E 树形dp+思维
比赛的时候看到题意没多想就放弃了.结果最后D也没做出来,还掉分了,所以还是题目做的太少,人太菜. 回到正题: 题意:一棵树,点带权值,然后求k个子连通块,使得k个连通块内所有的点权值相加作为分子除以k ...
- Codeforces 1179D 树形DP 斜率优化
题意:给你一颗树,你可以在树上添加一条边,问添加一条边之后的简单路径最多有多少条?简单路径是指路径中的点只没有重复. 思路:添加一条边之后,树变成了基环树.容易发现,以基环上的点为根的子树的点中的简单 ...
- CodeForces - 337D 树形dp
题意:一颗树上有且仅有一只恶魔,恶魔会污染距离它小于等于d的点,现在已经知道被污染的m个点,问恶魔在的可能结点的数量. 容易想到,要是一个点到(距离最远的两个点)的距离都小于等于d,那么这个点就有可能 ...
- CodeForces 219D 树形DP
D. Choosing Capital for Treeland time limit per test 3 seconds memory limit per test 256 megabytes i ...
- codeforces 337D 树形DP Book of Evil
原题直通车:codeforces 337D Book of Evil 题意:一棵n个结点的树上可能存在一个Evil,Evil危险范围为d,即当某个点与它的距离x<=d时,那么x是危险的. 现已知 ...
- Up and Down the Tree CodeForces - 1065F (树形dp)
链接 题目大意:给定$n$结点树, 假设当前在结点$v$, 有两种操作 $(1)$移动到$v$的子树内任意一个叶子上 $(2)$若$v$为叶子, 可以移动到距离$v$不超过$k$的祖先上 初始在结点$ ...
- codeforces 1053D 树形DP
题意:给一颗树,1为根节点,有两种节点,min或者max,min节点的值是它的子节点的值中最小的,max节点的值是它的子节点的值中最大的,若共有k个叶子,叶子的值依次为1~k. 问给每个叶子的值赋为几 ...
- Codeforces 735E 树形DP
题意:给你一棵树,你需要在这棵树上选择一些点染成黑色,要求染色之后树中任意节点到离它最近的黑色节点的距离不超过m,问满足这种条件的染色方案有多少种? 思路:设dp[x][i]为以x为根的子树中,离x点 ...
随机推荐
- 阿里云,腾讯云,等等的云 Ubuntu14.04升级16.04
16.04有很多好处.在此不说了 这几天来回折腾了各种的云,然后发现国内的都没有16.04 但是ubuntu可以直接在线升级 在此记下来升级的过程 不管是腾讯云也好 阿里云也好,或者别的什么云,只要是 ...
- 前端之JavaScript 01
一JavaScript介绍 js历史 1992年Nombas开发出C-minus-minus(C--)的嵌入式脚本语言(最初绑定在CEnvi软件中).后将其改名ScriptEase.(客户端执行的语言 ...
- LeetCode Valid Triangle Number
原题链接在这里:https://leetcode.com/problems/valid-triangle-number/description/ 题目: Given an array consists ...
- 利用DAC(Data-tier Application)实现数据库结构迁移
从一个存在的库,抽取其表结构,对象,权限等,再部署成一个不包含数据的"空库"的方法有很多种.如自带的Generate Scripts功能,自定义脚本提取创建脚本等. 在实际使用中, ...
- EL and JSTL(Jsp Standard Tag Libary)(转)
一.什么是 EL 语言. 表达式语言(EL)是 JSP 2.0 引入的一种计算和输出 Java 对象的简单语音. 二.EL 语言的作用. 为了使JSP写起来更加简单.表达式语言的灵感来自于 ECMAS ...
- SSM框架——整合搭建流程
1.首先创建maven工程,使用哪种方式进行创建都可以,可以参考博主之前的文章: <两种方式创建Maven项目[方式二]><两种方式创建Maven项目[方式一]> 2.先看看搭 ...
- 基于SQL调用Com组件来发送邮件
这个需求是公司有个文控中心,如果有用增删改了文件信息希望可以发邮件通知到有权限的人.当然方式很多. 这里是用数据库作业来完成 JOB+Com,这里用的com组件是Jmail 当然你需要把com组件放到 ...
- PS相关技术
PS相关长时间不用就忘记了,做个笔记,记录下来 (1)复制图层,可以将图层复制到另外的图层里去,这样,多个图层就可以编辑了 (2)通过建立选区,可以选择右键,通过剪切的图层,通过复制的图层将图片抠出来 ...
- java里的MouseLisetener接口的使用过程==========需要用组件是来注册侦听器
总结:通过匿名类来实现鼠标的监听或者 通过实现接口的方法都可以的 从此是实现MouseListener接口的方式 package com.a.b; import java.awt.Color; im ...
- Annotation之二:@Inherited注解继承情况
@Inherited annotation类型是被标注过的class的子类所继承.类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation. 子类中能否继承注解 ...