嘟嘟嘟

这道题可以说是[HNOI2003]消防局的设立的升级版。距离从2改为了d。

辛亏d只有20,这也就是一个切入点。

令f[u][j]表示u四周 j - 1的距离需要被覆盖,g[u][j]表示u可以像四周覆盖 j 的距离。

考虑转移方程,令v为u的其中一个儿子:

1.f[u][j]:直接从v延伸而来:f[u][j] = Σ f[v][j - 1]

2.g[u][j]:用前几个儿子已经得出的g[u][j]去覆盖v:g[u][j] = g[u][j] + f[v][j];或者用v覆盖u:g[now][j] = f[now][j +1] +g[v][j + 1],所以g[now][j] = min{g[now][j] + f[v][j], f[now][j + 1] + g[v][j + 1]}.

对于f,可能距离小的比大的还优,所以还要再求一遍前缀最小值:f[now][j] = min{f[now][k]} (0 <= k < j)

同理对于g,可能覆盖距离大的比距离小的还优,所以后缀最小值:g[now][j] = min{g[now][k]} (j < k <= d)

最后考虑的是初值:显然g[now][j] = c[now] (1 <= j <= d)。然后如果这个点B神可能出现,f[now][0] = g[now][0] = c[now],表示这个点需要覆盖。

(代码折叠坏啦)

 #include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define enter puts("")
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define rg register
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-;
const int maxn = 5e5 + ;
inline ll read()
{
ll ans = ;
char ch = getchar(), last = ' ';
while(!isdigit(ch)) {last = ch; ch = getchar();}
while(isdigit(ch)) {ans = (ans << ) + (ans << ) + ch - ''; ch = getchar();}
if(last == '-') ans = -ans;
return ans;
}
inline void write(ll x)
{
if(x < ) x = -x, putchar('-');
if(x >= ) write(x / );
putchar(x % + '');
} int n, d, m, c[maxn];
bool vis[maxn]; struct Edge
{
int nxt, to;
}e[maxn << ];
int head[maxn], ecnt = -;
void addEdge(int x, int y)
{
e[++ecnt] = (Edge){head[x], y};
head[x] = ecnt;
} int f[maxn][], g[maxn][];
void dfs(int now, int _f)
{
for(int i = ; i <= d; ++i) g[now][i] = c[now];
if(vis[now]) f[now][] = g[now][] = c[now];
g[now][d + ] = INF;
for(int i = head[now], v; i != -; i = e[i].nxt)
{
v = e[i].to;
if(v == _f) continue;
dfs(v, now);
for(int j = d; j >= ; --j) g[now][j] = min(g[now][j] + f[v][j], f[now][j + ] + g[v][j + ]);
for(int j = d; j >= ; --j) g[now][j] = min(g[now][j], g[now][j + ]);
f[now][] = g[now][];
for(int j = ; j <= d; ++j) f[now][j] += f[v][j - ];
for(int j = ; j <= d; ++j) f[now][j] = min(f[now][j], f[now][j - ]);
}
} int main()
{
Mem(head, -);
n = read(); d = read();
for(int i = ; i <= n; ++i) c[i] = read();
m = read();
for(int i = ; i <= m; ++i) {int x = read(); vis[x] = ;}
for(int i = ; i < n; ++i)
{
int x = read(), y = read();
addEdge(x, y); addEdge(y, x);
}
dfs(, );
write(f[][]), enter;
return ;
}

[JLOI2016/SHOI2016]侦察守卫的更多相关文章

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

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

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

    小R和B神正在玩一款游戏.这款游戏的地图由N个点和N-1条无向边组成,每条无向边连接两个点,且地图是连通的.换句话说,游戏的地图是一棵有N个节点的树. 游戏中有一种道具叫做侦查守卫,当一名玩家在一个点 ...

  3. P3267 [JLOI2016/SHOI2016]侦察守卫

    $ \color{#0066ff}{ 题目描述 }$ 小R和B神正在玩一款游戏.这款游戏的地图由N个点和N-1条无向边组成,每条无向边连接两个点,且地图是连通的.换句话说,游戏的地图是一棵有N个节点的 ...

  4. BZOJ4557:[JLOI2016/SHOI2016]侦察守卫——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4557 小R和B神正在玩一款游戏.这款游戏的地图由N个点和N-1条无向边组成,每条无向边连接两个点, ...

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

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

  6. Luogu 3267 [JLOI2016/SHOI2016]侦察守卫

    以后要记得复习鸭 BZOJ 4557 大佬的博客 状态十分好想,设$f_{x, i}$表示以覆盖完$x$为根的子树后还能向上覆盖$i$层的最小代价,$g_{x, i}$表示以$x$为根的子树下深度为$ ...

  7. Luogu3267 [JLOI2016/SHOI2016]侦察守卫 (树形DP)

    树形DP,一脸蒙蔽.看了题解才发现它转移状态与方程真不愧神题! \(f[x][y]\)表示\(x\)的\(y\)层以下的所有点都已经覆盖完,还需要覆盖上面的\(y\)层的最小代价. \(g[x][y] ...

  8. DP学习记录Ⅰ

    DP学习记录Ⅱ 前言 状态定义,转移方程,边界处理,这三部分想好了,就问题不大了.重点在状态定义,转移方程是基于状态定义的,边界处理是方便转移方程的开始的.因此最好先在纸上写出自己状态的意义,越详细越 ...

  9. bzoj 4557: [JLoi2016]侦察守卫 树归

    bzoj 4557: [JLoi2016]侦察守卫 设f[x][j]表示覆盖以x为根的子树的所有应该被覆盖的节点,并且以x为根的子树向下j层全部被覆盖的最小代价. 设g[x][j]表示与x距离大于j全 ...

随机推荐

  1. Firebird with lock

    Firebird 锁,默认是行级锁,即记录锁. 通常最常用的是 with lock ,即:将查出的所有记录都锁定,但允许其他事务读取,不允许其他事务更新.删除.本事务允许更新. 另一种 for upd ...

  2. Expression Blend实例中文教程(13) - 控件模板快速入门ControlTemplates

    上篇,介绍了控件样式(Style)和模板(Template)的基础概念,并且演示了使用Blend设计控件样式.本篇将继续介绍使用Blend设计自定义控件模板 - ControlTemplate.Con ...

  3. C#语言-08.序列化与反序列化

    a. 序列化:是将对象的状态存储到特定存储介质中的过程 i. 语法:public void Serialize(序列化过程的文件流,保存的对象) b. 返序列化:是从特定存储介质中将数据重新构建对象的 ...

  4. 关于逻辑删除标识字段value的设定

    为了容易记忆,项目里所有表记录的逻辑删除可以用“-1”(或其他值)来表示.

  5. idea快捷键、常用设置

      代码提示: code completion :ALT + / 选用Eclipse的keymap. 设置代码助手快捷键(keymap-basic) 代码上下行复制(Ctrl + Alt + Down ...

  6. 域对象中属性变更及感知session绑定的事件监听器

    域对象中属性的变更的时间监听器就是用来监听ServletContext,HttpSession,HttpServletRequest这三个对象中的属性变更信息事件的监听器.这三个监听器接口分别是Ser ...

  7. bat中实现代码拷贝到指定目录后启动命令行并更改默认路径

      ### window书写shell脚本,实现判断指定文件是否存在,存在就删除,然后复制新文件到此目录 ``` if exist "G:\test\test2\1.txt" (d ...

  8. sql-syscolumns,INFORMATION_SCHEMA.columns,sysobjects

    //计算表tb_Blog的字段个数 select count(*) from syscolumns where id=object_id('tb_Blog') 获取指定表的所有字段和字段类型 SELE ...

  9. python 多进程数据交互及共享

    多线程和多进程最大的不同在于,多进程中,同一个变量,各自有一份拷贝存在于每个进程中,互不影响,而多线程中,所有变量都由所有线程共享,所以,任何一个变量都可以被任何一个线程修改,因此,线程之间共享数据最 ...

  10. Ganglia安装

    一.rrdtool安装 1.1 安装依赖包 由于rrdtool依赖的包比较多,而且包之间也存在依赖,故使用yum安装由于服务器无法联网,故使用iso文件创建本地yum源,方法见下: (1)创建iso存 ...