【BZOJ 4557】【JLOI 2016】侦查守卫

来源:互联网 发布:m audio声卡驱动mac 编辑:程序博客网 时间:2024/05/01 03:26

鉴于省选杂题题意实在过于复杂QAQ之后就直接上题解了
这题如果想不出来正解的话。。估计只能拿10分,d=1的20分不知道能不能乱搞一发。。后面的几个点毫无区分度啊

令:
f[i][j]表示i这个节点下面j层以下都被覆盖的代价
g[i][j]表示以i这个节点为根的子树、以及向上长度为j的一条链都被覆盖的代价

从下往上dp显然。这个g数组我一开始想到了,因为当前i这个点对上面的影响只有向上长度为d的一条链。但是这个f数组太鬼畜了,后来想一下,当前点所能影响的范围直径为d,那么就要记录d下面的节点。
首先假设当前点x要放守卫,那么如果不放守卫,所更新的范围就是f[x][0-d]和g[x][0-d]。f数组的更新是显然的,只要对一个一个加进来就行了;g数组的方法有点复杂,要在x的孩子中找出一个y,让y伸出一条链覆盖x上面[0-d]个节点,同时x下面的[0-d]个节点也会被覆盖,所以这个时候要加上一个f数组。
状态转移方程就不写了,程序里面还是比较清晰的。

#include<cmath>#include<cstdio>#include<vector>#include<cstring>#include<iomanip>#include<stdlib.h>#include<iostream>#include<algorithm>#define ll long long#define inf 2100000000#define mod 1000000007#define N 600000using namespace std;int n,m,x,y,d,i;int w[N],b[N],f[N][30],g[N][30];vector<int> e[N];void dfs(int x,int fa){    int i,j,y;    if (b[x] == 1) f[x][0] = g[x][0] = w[x];    for (i = 1;i <= d; i++) g[x][i] = w[x];    g[x][d+1] = inf;    for (i = 0;i < e[x].size(); i++)        if (e[x][i] != fa)            {                y = e[x][i];                dfs(y,x);                for (j = 0;j <= d; j++) g[x][j] = min(g[x][j]+f[y][j],g[y][j+1]+f[x][j+1]);                for (j = d;j >= 0; j--) g[x][j] = min(g[x][j],g[x][j+1]);                f[x][0] = g[x][0];                for (j = 1;j <= d + 1; j++) f[x][j] += f[y][j-1];                for (j = 1;j <= d + 1; j++) f[x][j] = min(f[x][j],f[x][j-1]);            }}int main(){    scanf("%d%d",&n,&d);    for (i = 1;i <= n; i++) scanf("%d",&w[i]);    scanf("%d",&m);    for (i = 1;i <= m; i++) {scanf("%d",&x); b[x] = 1;}    for (i = 1;i < n; i++)        {            scanf("%d%d",&x,&y);            e[x].push_back(y); e[y].push_back(x);        }    dfs(1,0);    printf("%d",f[1][0]);    return 0;}
0 0
原创粉丝点击