BZOJ4557:[JLOI2016/SHOI2016]侦察守卫——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=4557
小R和B神正在玩一款游戏。这款游戏的地图由N个点和N-1条无向边组成,每条无向边连接两个点,且地图是连通的。换句话说,游戏的地图是一棵有N个节点的树。
游戏中有一种道具叫做侦查守卫,当一名玩家在一个点上放置侦查守卫后,它可以监视这个点以及与这个点的距离在D以内的所有点。这里两个点之间的距离定义为它们在树上的距离,也就是两个点之间唯一的简单路径上所经过边的条数。在一个点上放置侦查守卫需要付出一定的代价,在不同点放置守卫的代价可能不同。
现在小R知道了所有B神可能会出现的位置,请你计算监视所有这些位置的最小代价。
dp状态很好想,但是这个式子我菜我是真的推不出来,其他的巨佬切题的速度叹为观止,只能感叹我的智商摆在这里。
参考:https://www.luogu.org/blog/zcysky/solution-p3267
一眼是个树形dp,二眼$d$很小,可以直接做成一维状态,那么直接设$f[i][j]$为$i$子树从$i$往下$j$层都没有覆盖的代价,$g[i][j]$为$i$的子树全覆盖,往上还可以覆盖$j$层的代价。二者正好是互补的。
(PS:层数也包括i本身,换句话说,$j=0$时$i$并没有被覆盖,我在这里纠结了很久。)
(PPS:既然$g[i][j]$都可以覆盖上$j$层,那它也能覆盖下$j$层。)
之后对于dp式子慢慢剖析因为我自己都云里雾里的。
边界就是当点$u$为关键点时$f[u][0]=g[u][0]=w[u]$这个点一定是要放一个的,如果不是的话显然我们就不需要放了,初值为0。
初始化就不说了。
对于每个儿子结点v,我们有:
$g[u][j]=min(g[u][j]+f[v][j],g[v][j+1]+f[u][j+1])$(所以明白f和g是互补的才能看懂)
当然也有可能出现这种的:$g[u][j]=min(g[u][j],g[u][j+1])$
推完g来推f,首先$f[u][0]=g[u][0]$因为此时二者状态等价。
然后显然的,$f[u][j]+=f[v][j-1]$
以及也有可能出现这种的:$f[u][j]=min(f[u][j],f[u][j-1])$
(所以其实核心还是在状态含义上而非式子,含义搞懂式子就很显然了。)
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=5e5+;
const int D=;
const int INF=1e9;
inline int read(){
int X=,w=;char ch=;
while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
while(isdigit(ch))X=(X<<)+(X<<)+(ch^),ch=getchar();
return w?-X:X;
}
struct node{
int to,nxt;
}e[N*];
int n,d,m,cnt,head[N],w[N];
int f[N][D],g[N][D];
bool im[N];
inline void add(int u,int v){
e[++cnt].to=v;e[cnt].nxt=head[u];head[u]=cnt;
}
void dfs(int u,int fa){
if(im[u])f[u][]=g[u][]=w[u];
for(int i=;i<=d;i++)g[u][i]=w[u];
g[u][d+]=INF;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(v==fa)continue;
dfs(v,u);
for(int j=d;j>=;j--)g[u][j]=min(g[u][j]+f[v][j],g[v][j+]+f[u][j+]);
for(int j=d;j>=;j--)g[u][j]=min(g[u][j],g[u][j+]);
f[u][]=g[u][];
for(int j=;j<=d+;j++)f[u][j]+=f[v][j-];
for(int j=;j<=d+;j++)f[u][j]=min(f[u][j],f[u][j-]);
}
}
int main(){
n=read(),d=read();
for(int i=;i<=n;i++)w[i]=read();
m=read();
for(int i=;i<=m;i++)im[read()]=;
for(int i=;i<n;i++){
int u=read(),v=read();
add(u,v);add(v,u);
}
dfs(,);
printf("%d\n",f[][]);
return ;
}
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+
+++++++++++++++++++++++++++++++++++++++++++
BZOJ4557:[JLOI2016/SHOI2016]侦察守卫——题解的更多相关文章
- P3267 [JLOI2016/SHOI2016]侦察守卫
$ \color{#0066ff}{ 题目描述 }$ 小R和B神正在玩一款游戏.这款游戏的地图由N个点和N-1条无向边组成,每条无向边连接两个点,且地图是连通的.换句话说,游戏的地图是一棵有N个节点的 ...
- 洛谷 P3267 [JLOI2016/SHOI2016]侦察守卫(树形dp)
题面 luogu 题解 树形\(dp\) \(f[x][y]表示x的y层以下的所有点都已经覆盖完,还需要覆盖上面的y层的最小代价.\) \(g[x][y]表示x子树中所有点都已经覆盖完,并且x还能向上 ...
- 洛谷 P3267 - [JLOI2016/SHOI2016]侦察守卫(树形 dp)
洛谷题面传送门 经典题一道,下次就称这种"覆盖距离不超过 xxx 的树形 dp"为<侦察守卫模型> 我们考虑树形 \(dp\),设 \(f_{x,j}\) 表示钦定了 ...
- Luogu3267 [JLOI2016/SHOI2016]侦察守卫 (树形DP)
树形DP,一脸蒙蔽.看了题解才发现它转移状态与方程真不愧神题! \(f[x][y]\)表示\(x\)的\(y\)层以下的所有点都已经覆盖完,还需要覆盖上面的\(y\)层的最小代价. \(g[x][y] ...
- [JLOI2016/SHOI2016]侦察守卫(树形dp)
小R和B神正在玩一款游戏.这款游戏的地图由N个点和N-1条无向边组成,每条无向边连接两个点,且地图是连通的.换句话说,游戏的地图是一棵有N个节点的树. 游戏中有一种道具叫做侦查守卫,当一名玩家在一个点 ...
- [JLOI2016/SHOI2016]侦察守卫
嘟嘟嘟 这道题可以说是[HNOI2003]消防局的设立的升级版.距离从2改为了d. 辛亏d只有20,这也就是一个切入点. 令f[u][j]表示u四周 j - 1的距离需要被覆盖,g[u][j]表示u可 ...
- Luogu 3267 [JLOI2016/SHOI2016]侦察守卫
以后要记得复习鸭 BZOJ 4557 大佬的博客 状态十分好想,设$f_{x, i}$表示以覆盖完$x$为根的子树后还能向上覆盖$i$层的最小代价,$g_{x, i}$表示以$x$为根的子树下深度为$ ...
- BZOJ4557 JLoi2016 侦察守卫 【树形DP】*
BZOJ4557 JLoi2016 侦察守卫 Description 小R和B神正在玩一款游戏.这款游戏的地图由N个点和N-1条无向边组成,每条无向边连接两个点,且地图是连通的.换句话说,游戏的地图是 ...
- [BZOJ4557][JLOI2016]侦察守卫(树形DP)
首先可以确定是树形DP,但这里存在跨子树的信息传递问题,这里就需要“借”的思想. f[i][j]表示i子树内所有点都被覆盖到,且i以外j层内的点都能被覆盖到 的方案数. g[i][j]表示i子树内离i ...
随机推荐
- Java String 字符串类细节探秘
一. 字符串基本知识要点 字符串类型String是Java中最常用的引用类型.我们在使用Java字符串的时候,通常会采用两种初始化的方式:1. String str = "Hello Wor ...
- C#原型模式
如下: [Serializable] public class ModelNewTable : ICloneable { public object Clone() { using (var stre ...
- dva框架之redux相关
dva封装了redux,减少很多重复代码比如action reducers 常量等,本文简单介绍dva redux操作流程. 利用官网的一个加减操作小实例来操作: dva所有的redux操作是放在mo ...
- RabbitMQ基础教程之使用进阶篇
RabbitMQ基础教程之使用进阶篇 相关博文,推荐查看: RabbitMq基础教程之安装与测试 RabbitMq基础教程之基本概念 RabbitMQ基础教程之基本使用篇 I. 背景 前一篇基本使用篇 ...
- Objective-C 点语法 成员变量的作用域 @property和@synthesize关键字 id类型
点语法 1.利用点语法替换set方法和get方法 方法调用 Student *stu = [Student new]; [stu setAge : 18]; int age = [stu age]; ...
- Siki_Unity_1-6_C#编程初级教程(未学)
Unity 1-6 C#编程初级教程 任务1:C#和.Net框架 C#是.Net里的一个成分 2002年微软发布第一个.Net框架(多平台,行业标准,安全性) .Net框架 IDE编程工具 --产生- ...
- js for循环实例
1.求1-100的寄数和? //2.奇数求和 var ppt=0 for(var i=1;i<=100;i+=2){ ppt+=i } 2.求1-100的偶数和 var num=0 for(va ...
- leetcode-峰值检测
寻找峰值 峰值元素是指其值大于左右相邻值的元素. 给定一个输入数组 nums,其中 nums[i] ≠ nums[i+1],找到峰值元素并返回其索引. 数组可能包含多个峰值,在这种情况下,返回 ...
- [Data Structures and Algorithms - 1] Introduction & Mathematics
References: 1. Stanford University CS97SI by Jaehyun Park 2. Introduction to Algorithms 3. Kuangbin' ...
- UVa 1225 - Digit Counting - ACM/ICPC Danang 2007 解题报告 - C语言
1.题目大意 把前n$(n\le 10000)$个整数顺次写在一起:12345678910111213……计算0~9各出现了多少次. 2.思路 第一想法是打表,然而觉得稍微有点暴力.不过暂时没有想到更 ...