题目大意

一颗 \(n(1\leq n\leq 5\times 10^5)\) 个节点的树,在某一点 \(i\) 花费 \(w_{i}(w_{i}\leq 1000)\) 放置一个侦察守卫后可以监视到所有到 \(i\) 的距离 \(\leq d(d\leq 20)\) 的点, 有 \(m(m\leq n)\)个给定的关键节点需要监视,求能够监视到全部 \(m\) 个节点所需要的最小花费。

思路

设 \(f[i,x]\) 为监视到以 \(i\) 为根的子树中的全部关键点,并且可以向上监视到距离不小于 \(i\) 的节点的最小花费; \(g[i,x]\) 为至少监视到了以 \(i\) 为根的子树中的全部的与 \(i\) 的距离 \(\geq x\) 的关键点所需要的最小花费。在合并子树的过程中,对于 \(i\) 的每一个儿子 \(j\) ,我们可以得到:

\[f[i,x]=min(f[i,x]+g[j,x],g[i,x+1]+f[j,x+1])
\]
\[g[i,x]=g[i,x]+g[j,x-1]
\]

此外,由我们对状态的定义,显然有:

\[f[i,x]=min(f[i,x],f[i,x+1])
\]
\[g[i,x]=min(g[i,x],g[i,x-1])
\]

对于初始值,一开始先将所有 \(f\) 初始为 \(inf\) 。考虑到每一个子树一开始只有一个根节点 \(i\) ,于是,如果 \(i\) 是关键点, 那么 \(g[i,0]=f[i,0]=w_{i}\) ,否则, \(g[i,0]=f[i,0]=0\) ,因为此时 \(g\) 与 \(f\) 都恰好表示仅考虑节点 \(i\) 时的情况。如果 \(x\neq 0\) ,因为要向上监视,所以此处必须有一个侦察守卫,所以对于所有 \(1\leq x\leq d\) , \(f[i,x]=w_{i}\) 。

在每次与一个子树合并时,要先计算 \(f\) ,后计算 \(g\) 。因为 \(f\) 的转移方程中需要用到一个尚未与新的子树合并的 \(g\) 。此外由于 \(g[i,0]\) 不能通过转移方程得到,每次合并时计算完 \(f\) 后,需要令 \(g[i,0]=f[i,0]\) 。复杂度 \(O(nd)\) 。

代码

#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
#define all(x) x.begin(),x.end()
//#define int LL
//#define lc p*2+1
//#define rc p*2+2
#define endl '\n'
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#pragma warning(disable : 4996)
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
const double eps = 1e-8;
const LL MOD = 1000000007;
const LL mod = 998244353;
const int maxn = 500010; vector<int>G[maxn];
int N, D, M, W[maxn];
bool key[maxn];
int f[maxn][25], g[maxn][25]; void add_edge(int from, int to)
{
G[from].push_back(to);
G[to].push_back(from);
} void dfs(int v, int p)
{
if (key[v])
f[v][0] = g[v][0] = W[v];
else
f[v][0] = g[v][0] = 0;
for (int i = 1; i <= D; i++)
f[v][i] = W[v];
for (int i = 0; i < G[v].size(); i++)
{
int to = G[v][i];
if (to == p)
continue;
dfs(to, v);
for (int j = 0; j <= D; j++)
f[v][j] = min(f[v][j] + g[to][j], f[to][j + 1] + g[v][j + 1]);
for (int j = D; j >= 0; i--)
f[v][j] = min(f[v][j], f[v][j + 1]);
g[v][0] = f[v][0];
for (int j = 1; j <= D; j++)
g[v][j] += g[to][j - 1];
for (int j = 1; j <= D; j++)
g[v][j] = min(g[v][j], g[v][j - 1]);
}
} void solve()
{
int ans = inf;
dfs(1, 0);
for (int i = 0; i <= D; i++)
ans = min(f[1][i], ans);
cout << ans << endl;
} int main()
{
IOS;
memset(f, inf, sizeof(f));
cin >> N >> D;
for (int i = 1; i <= N; i++)
cin >> W[i];
cin >> M;
int b;
for (int i = 1; i <= M; i++)
{
cin >> b;
key[b] = true;
}
int u, v;
for (int i = 1; i < N; i++)
{
cin >> u >> v;
add_edge(u, v);
}
solve(); return 0;
}

洛谷P3267.侦察守卫的更多相关文章

  1. 洛谷 P3267 - [JLOI2016/SHOI2016]侦察守卫(树形 dp)

    洛谷题面传送门 经典题一道,下次就称这种"覆盖距离不超过 xxx 的树形 dp"为<侦察守卫模型> 我们考虑树形 \(dp\),设 \(f_{x,j}\) 表示钦定了 ...

  2. 洛谷 P3267 [JLOI2016/SHOI2016]侦察守卫(树形dp)

    题面 luogu 题解 树形\(dp\) \(f[x][y]表示x的y层以下的所有点都已经覆盖完,还需要覆盖上面的y层的最小代价.\) \(g[x][y]表示x子树中所有点都已经覆盖完,并且x还能向上 ...

  3. 洛谷1640 bzoj1854游戏 匈牙利就是又短又快

    bzoj炸了,靠离线版题目做了两道(过过样例什么的还是轻松的)但是交不了,正巧洛谷有个"大牛分站",就转回洛谷做题了 水题先行,一道傻逼匈牙利 其实本来的思路是搜索然后发现写出来类 ...

  4. 洛谷P1352 codevs1380 没有上司的舞会——S.B.S.

    没有上司的舞会  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond       题目描述 Description Ural大学有N个职员,编号为1~N.他们有 ...

  5. 洛谷P1108 低价购买[DP | LIS方案数]

    题目描述 “低价购买”这条建议是在奶牛股票市场取得成功的一半规则.要想被认为是伟大的投资者,你必须遵循以下的问题建议:“低价购买:再低价购买”.每次你购买一支股票,你必须用低于你上次购买它的价格购买它 ...

  6. 洛谷 P2701 [USACO5.3]巨大的牛棚Big Barn Label:二维数组前缀和 你够了 这次我用DP

    题目背景 (USACO 5.3.4) 题目描述 农夫约翰想要在他的正方形农场上建造一座正方形大牛棚.他讨厌在他的农场中砍树,想找一个能够让他在空旷无树的地方修建牛棚的地方.我们假定,他的农场划分成 N ...

  7. 洛谷P1710 地铁涨价

    P1710 地铁涨价 51通过 339提交 题目提供者洛谷OnlineJudge 标签O2优化云端评测2 难度提高+/省选- 提交  讨论  题解 最新讨论 求教:为什么只有40分 数组大小一定要开够 ...

  8. 洛谷P1371 NOI元丹

    P1371 NOI元丹 71通过 394提交 题目提供者洛谷OnlineJudge 标签云端评测 难度普及/提高- 提交  讨论  题解 最新讨论 我觉得不需要讨论O long long 不够 没有取 ...

  9. 洛谷P1538迎春舞会之数字舞蹈

    题目背景 HNSDFZ的同学们为了庆祝春节,准备排练一场舞会. 题目描述 在越来越讲究合作的时代,人们注意的更多的不是个人物的舞姿,而是集体的排列. 为了配合每年的倒计时,同学们决定排出——“数字舞蹈 ...

随机推荐

  1. Linux创建运行C/C++代码

    不同于在Windows操作系统下借助IDE运行C++程序,Linux操作系统可以使用g++编译 创建文件及编译文件的流程  1. 先进入某一文件目录下,创建一个文件(也可以用mkdir创建文件) to ...

  2. 什么是HTTP? HTTP 和 HTTPS 的区别?

    转载地址: 面试官:什么是HTTP? HTTP 和 HTTPS 的区别? 一.HTTP HTTP (HyperText Transfer Protocol),即超文本运输协议,是实现网络通信的一种规范 ...

  3. CKKS :Part1,普通编码/解码

    这篇文章,翻译于:[CKKS EXPLAINED: PART 1, VANILLA ENCODING AND DECODING] 主要介绍为CKKS中编码/解码做铺垫,讲一些基础知识 介绍 同态加密是 ...

  4. 计算机电子书 2019 BiliDrive 备份

    下载方式 pip install BiliDriveEx bdex download <link> 链接 文档 链接 传智播客轻松搞定系列 C.C++.Linux.设计模式.7z (33. ...

  5. for、while、do...while循环结构

    循环结构分别有: while 循环 do...while 循环 for 循环 在Java5中引入了一种主要用于数组的增强型for循环 while 循环 while是最基本的循环,它的结构为: whil ...

  6. python编写购物车-实时购买

    本次编写的是实时购买(输入商品直接进行购买),余额不足可以进行充值或结束购物 1 goods = [ 2 {"name": "电脑", "price& ...

  7. (DDS)正弦波形发生器——幅值、频率、相位可调(二)

    (DDS)正弦波形发生器--幅值.频率.相位可调(二) 主要关于调相方面 一.项目任务: 设计一个幅值.频率.相位均可调的正弦波发生器. 频率每次增加10kHz 相位每次增加 PI/2 幅值每次增加两 ...

  8. String类为什么可以直接赋值

    在研究String直接赋值与new String的区别之前我们需要先了解java中的字符串常量池的概念 字符串常量池 String类是我们平常项目中使用频率非常高的一种对象类型,jvm为了提升性能和减 ...

  9. linux c 线程相关函数

    线程相关函数(1)-pthread_create(), pthread_join(), pthread_exit(), pthread_cancel() 创建取消线程 一. pthread_creat ...

  10. PHP宝典面试笔试题目

    PHP宝典面试笔试题目 来自<PHP程序员面试笔试宝典>,涵盖了近三年了各大型企业常考的PHP面试题,针对面试题提取出来各种面试知识也涵盖在了本书. PHP题目 [真题68] (    ) ...