下称放置守卫的点为监控点。设f[i][j]为i子树中深度最大的未被监视点与i的距离不超过j时的最小代价,g[i][j]为i子树中距离i最近的监控点与i的距离不超过j且i子树内点全部被监视时的最小代价。开始觉得这只能设成三维状态对这种二维的纠结了半天要怎么处理子树内有点未被监视但监控点的范围可以延伸到子树外的情况冷静了好长时间终于发现自己果然是个弱智既然子树内有点要被监视在子树外监控这个点的点之后带来的效果就肯定要比子树内的监控点强所以根本不用管子树内的监控点了不写标点发泄一下内心的心态爆炸。

  考虑转移。对于f[i][j],显然有f[i][j]=Σf[son][j-1],f[i][0]=Σg[son][d](g本身就可以看做是f的第二维在负数下的拓展)。对于g[i][j],枚举与i号点最近的监控点在哪棵子树,则有g[i][j]=g[k][j-1]+Σf[son][d-j-1]。g[i][d]特殊处理,如果其不要求被监视则g[i][d]=Σg[son][d],虽然不太符合定义但正确性显然,否则g[i][d]=g[k][d-1]+Σg[son][d]。然后考虑将i号点设置为监控点,则有g[i][0]=a[i]+Σf[son][d-1]。最后对所有f和g取min。

  感觉写的莫名其妙,也莫名其妙就过掉了。要是没法1A的话估计得调一年。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 500010
#define inf 1000000000
#define M 22
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')) c=getchar();return c;}
int gcd(int n,int m){return m==?n:gcd(m,n%m);}
int n,d,m,a[N],p[N],f[N][M],g[N][M],t=;
bool flag[N];
struct data{int to,nxt;
}edge[N<<];
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
void dfs(int k,int from)
{
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=from) dfs(edge[i].to,k);
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=from)
{
f[k][]+=g[edge[i].to][d];
for (int j=;j<=d;j++)
f[k][j]+=f[edge[i].to][j-];
}
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=from) g[k][]+=f[edge[i].to][d-];
g[k][]+=a[k];for (int i=;i<=d;i++) g[k][i]=g[k][];
for (int j=;j<d;j++)
{
int tot=;
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=from) tot+=f[edge[i].to][d-j-];
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=from) g[k][j]=min(g[k][j],g[edge[i].to][j-]-f[edge[i].to][d-j-]+tot);
}
int tot=;
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=from) tot+=g[edge[i].to][d];
if (flag[k])
{
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=from) g[k][d]=min(g[k][d],g[edge[i].to][d-]-g[edge[i].to][d]+tot);
}
else g[k][d]=tot;
for (int i=;i<=d;i++) g[k][i]=min(g[k][i],g[k][i-]);
f[k][]=min(f[k][],g[k][d]);
for (int i=;i<=d;i++) f[k][i]=min(f[k][i],f[k][i-]);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj4557.in","r",stdin);
freopen("bzoj4557.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
n=read(),d=read();
for (int i=;i<=n;i++) a[i]=read();
m=read();
for (int i=;i<=m;i++) flag[read()]=;
for (int i=;i<n;i++)
{
int x=read(),y=read();
addedge(x,y),addedge(y,x);
}
dfs(,);
cout<<g[][d];
return ;
}

BZOJ4557 JLOI2016侦察守卫(树形dp)的更多相关文章

  1. [BZOJ4557][JLOI2016]侦察守卫(树形DP)

    首先可以确定是树形DP,但这里存在跨子树的信息传递问题,这里就需要“借”的思想. f[i][j]表示i子树内所有点都被覆盖到,且i以外j层内的点都能被覆盖到 的方案数. g[i][j]表示i子树内离i ...

  2. 【BZOJ4557】[JLoi2016]侦察守卫 树形DP

    [BZOJ4557][JLoi2016]侦察守卫 Description 小R和B神正在玩一款游戏.这款游戏的地图由N个点和N-1条无向边组成,每条无向边连接两个点,且地图是连通的.换句话说,游戏的地 ...

  3. BZOJ4557 JLoi2016 侦察守卫 【树形DP】*

    BZOJ4557 JLoi2016 侦察守卫 Description 小R和B神正在玩一款游戏.这款游戏的地图由N个点和N-1条无向边组成,每条无向边连接两个点,且地图是连通的.换句话说,游戏的地图是 ...

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

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

  5. bzoj4557 [JLoi2016]侦察守卫——DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4557 见这位的博客:https://www.cnblogs.com/Narh/p/91403 ...

  6. bzoj千题计划272:bzoj4557: [JLoi2016]侦察守卫

    http://www.lydsy.com/JudgeOnline/problem.php?id=4557 假设当前到了x的子树,现在是合并 x的第k个子树 f[x][j] 表示x的前k-1个子树该覆盖 ...

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

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

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

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

  9. 动态规划(树形DP):LNOI 2016 侦察守卫

    Sample Input 12 2 8 9 12 6 1 1 5 1 4 8 10 6 10 1 2 3 5 6 7 8 9 10 11 1 3 2 3 3 4 4 5 4 6 4 7 7 8 8 9 ...

随机推荐

  1. 字符编码 ASCII unicode UTF-8

    字符串也是一种数据类型,但是,字符串比较特殊的是还有一个编码问题. 因为计算机只能处理数字,如果要处理文本,就必须先把文本转换为数字才能处理.最早的计算机在设计时采用8个比特(bit)作为一个字节(b ...

  2. 内存泄漏导致程序killed

    示例程序: #include<stdio.h> #include<unistd.h> int main() { ) { *]; } ; } 执行结果: 程序消耗完内存会被kil ...

  3. (数据科学学习手札23)决策树分类原理详解&Python与R实现

    作为机器学习中可解释性非常好的一种算法,决策树(Decision Tree)是在已知各种情况发生概率的基础上,通过构成决策树来求取净现值的期望值大于等于零的概率,评价项目风险,判断其可行性的决策分析方 ...

  4. python2.7入门---字符串

        这次咱们就来看一下python的字符串类型.首先我们要知道,字符串是 Python 中最常用的数据类型.我们可以使用引号('或")来创建字符串.创建字符串很简单,只要为变量分配一个值 ...

  5. PHP.40-TP框架商城应用实例-后台15-商品属性与库存量1-不同商品(唯一属性、可选属性),属性类型

    思路: 1.不同商品属于不同的类型,如:手机.服装.电脑等类型 2.不同的类型有不同的属性,其中分为唯一属性和可选属性,如服装:可选属性{尺寸:S,M,L……;颜色:白色,黑色……}唯一属性:材质 首 ...

  6. Git中从远程的分支获取最新的版本到本地——两种命令

    Git中从远程的分支获取最新的版本到本地有这样2个命令: 1. git fetch:相当于是从远程获取最新版本到本地,不会自动merge Git fetch origin master git log ...

  7. 前端学习webpack

    ### 模块化- 为了保证代码充分解耦,一个大的项目拆分成互相依赖的一个一个的小的模块,最后再通过简单的方式合并在一起- 每一个js文件都可以看成一个单独的模块在node这边(服务器端),提出Comm ...

  8. guacamole实现上传下载

    目录 1. 源码解读 2. 上传下载的核心代码 分析的入手点,查看websocket连接的frame 看到首先服务端向客户端发送了filesystem请求,紧接着浏览器向服务端发送了get请求,并且后 ...

  9. Extjs报错:isField为空或不是对象

             在做Extjs开发的时候,有时候会碰到一个奇怪的问题,就是报错说"isField为空或不是对象",经过调试发现是一个数组,显示的长度是21,但是数组里面的个数只有 ...

  10. react children技巧总结

    在使用该技巧时,建议先看一下相关的知识,点我查看 假如使用该属性时,想把父组件的所有属性及部分方法传递给子组件,该怎么办呢?看代码 const Child = ({ doSomething, valu ...