树上覆盖距离不超过 d 的状态设计
[JLOI2016/SHOI2016]侦察守卫
设 \(f_{x,j}\) 表示 \(x\) 子树内必须要被覆盖的点都覆盖,\(x\) 的 \(1 \sim j\) 级祖先都被覆盖了的最小代价。
设 \(g_{x,j}\) 表示 \(x\) 子树内,和 \(x\) 距离 \(\geq j\) 的都被覆盖了,对于和 \(x\) 距离 \(< j\) 的不做要求,对于 \(x\) 的祖先不做要求的最小代价。
一个性质是 \(\forall i, j ,g_{x,i} \leq f_{x,j}\)。
因为后者包含了前者,还会多,所以一定会更多。
转移如何转移呢?
\(g_{x,0} = f_{x,0}\) 等价于都子树覆盖其他都不管
\(g_{x,i}=g_{x,i}+g_{to,i-1}\) 因为距离儿子为 \(i - 1\) 的都被覆盖了,那么也就是距离 \(x\) 为 \(i - 1\) 的被覆盖了。
\(f_{x,i}=\min(f_{x,i}+g_{to,i},g_{x,i+1}+f_{to,i+1})\) 首先本身可以往上覆盖 \(i\) 的话,就也能向下覆盖 \(i - 1\),那么只要儿子 \(\geq i\) 的被覆盖了就好了。
同时,如果距离儿子 \(\geq i\) 的都被覆盖了,然后那么让七中一个儿子选择向上覆盖 \(i + 1\) 就好了。
当然的,根据定义,同时还有:
\(f_{x,i} = \min\{ f_{x, i - 1}\}, g_{x,i} = \min\{ g_{x, i - 1}\}\)
然后就可以直接转移了
// 德丽莎你好可爱德丽莎你好可爱德丽莎你好可爱德丽莎你好可爱德丽莎你好可爱
// 德丽莎的可爱在于德丽莎很可爱,德丽莎为什么很可爱呢,这是因为德丽莎很可爱!
// 没有力量的理想是戏言,没有理想的力量是空虚
#include <bits/stdc++.h>
#define LL long long
using namespace std;
char ibuf[1 << 15], *p1, *p2;
#define getchar() (p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, 1 << 15, stdin), p1==p2) ? EOF : *p1++)
inline int read() {
char ch = getchar(); int x = 0, f = 1;
while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
return x * f;
}
void print(LL x) {
if (x > 9) print(x / 10);
putchar(x % 10 + '0');
}
template<class T> bool chkmin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool chkmax(T &a, T b) { return a < b ? (a = b, true) : false; }
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define repd(i, l, r) for (int i = (l); i >= (r); i--)
#define REP(i, l, r) for (int i = (l); i < (r); i++)
const int N = 5e5 + 5, inf = 3e7;
int n, m, d, w[N], vis[N], num, nex[N << 1], first[N << 1], v[N << 1];
void add(int from,int to) {
nex[++num] = first[from]; first[from] = num; v[num] = to;
}
int f[N][22], g[N][22];
void dfs(int x,int fa) {
rep (i, 1, d) f[x][i] = w[x]; f[x][d + 1] = inf;
if (vis[x]) f[x][0] = g[x][0] = w[x];
for (int i = first[x]; i; i = nex[i]) {
int to = v[i];
if (to == fa) continue;
dfs(to, x);
repd (i, d, 0) f[x][i] = min(f[x][i] + g[to][i], g[x][i + 1] + f[to][i + 1]);
repd (i, d, 0) f[x][i] = min(f[x][i], f[x][i + 1]);
g[x][0] = f[x][0];
rep (i, 1, d) g[x][i] = g[x][i] + g[to][i - 1];
rep (i, 1, d) g[x][i] = min(g[x][i], g[x][i - 1]);
}
}
void solve() {
n = read(), d = read();
rep (i, 1, n) w[i] = read();
m = read();
rep (i, 1, m) { int x = read(); vis[x] = 1; }
REP (i, 1, n) {
int x = read(), y = read();
add(x, y), add(y, x);
}
dfs(1, 0);
cout << g[1][0] << "\n";
}
signed main () {
#ifdef LOCAL_DEFINE
freopen("1.in", "r", stdin);
freopen("1.ans", "w", stdout);
#endif
int T = 1; while (T--) solve();
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}
hdu5290 Bombing plan
是同样的,改下就好了!
但是这个傻卵玩意多测,还返回的奇奇怪怪的。
// 德丽莎你好可爱德丽莎你好可爱德丽莎你好可爱德丽莎你好可爱德丽莎你好可爱
// 德丽莎的可爱在于德丽莎很可爱,德丽莎为什么很可爱呢,这是因为德丽莎很可爱!
// 没有力量的理想是戏言,没有理想的力量是空虚
#include <bits/stdc++.h>
#define LL long long
using namespace std;
char ibuf[1 << 15], *p1, *p2;
#define getchar() (p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, 1 << 15, stdin), p1==p2) ? EOF : *p1++)
inline int read() {
char ch = getchar(); int x = 0, f = 1;
while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
return x * f;
}
void print(LL x) {
if (x > 9) print(x / 10);
putchar(x % 10 + '0');
}
template<class T> bool chkmin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool chkmax(T &a, T b) { return a < b ? (a = b, true) : false; }
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define repd(i, l, r) for (int i = (l); i >= (r); i--)
#define REP(i, l, r) for (int i = (l); i < (r); i++)
const int N = 1e5 + 5, inf = N + 1;
int n, m, w[N], num, nex[N << 1], first[N << 1], v[N << 1], d = 100;
void add(int from,int to) {
nex[++num] = first[from]; first[from] = num; v[num] = to;
}
int f[N][102], g[N][102];
void dfs(int x,int fa) {
rep (i, 0, w[x]) f[x][i] = 1;
rep (i, w[x] + 1, d + 1) f[x][i] = inf;
rep (i, 0, d + 1) g[x][i] = 0;
g[x][0] = 1;
for (int j = first[x]; j; j = nex[j]) {
int to = v[j];
if (to == fa) continue;
dfs(to, x);
repd (i, d, 0) f[x][i] = min(f[x][i] + g[to][i], g[x][i + 1] + f[to][i + 1]);
repd (i, d, 0) f[x][i] = min(f[x][i], f[x][i + 1]);
g[x][0] = f[x][0];
rep (i, 1, d) g[x][i] = g[x][i] + g[to][i - 1];
rep (i, 1, d) g[x][i] = min(g[x][i], g[x][i - 1]);
}
}
void solve() {
while (cin >> n) {
rep (i, 1, n) cin >> w[i];
rep (i, 1, num) nex[i] = first[i] = v[i] = 0;
num = 0;
REP (i, 1, n) {
int x, y; cin >> x >> y;
add(x, y), add(y, x);
}
dfs(1, 0);
cout << g[1][0] << "\n";
}
}
signed main () {
#ifdef LOCAL_DEFINE
freopen("1.in", "r", stdin);
freopen("1.ans", "w", stdout);
#endif
ios :: sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int T = 1; while (T--) solve();
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}