NOIP2018 保卫王国(动态DP)

题意

求最小权值点覆盖。

m m 次询问,每次给出两个点,分别要求每个点必须选或必须不选,输出每次的最小权值覆盖或者无解输出 1 -1

题解

强制选或者不选可以看做修改权值为 ± \pm\infin

那么就是这道板题了。

CODE

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
template<class T>inline void read(T &x) {
	char ch; int flg=1; while(!isdigit(ch=getchar()))if(ch=='-')flg=-flg;
	for(x=ch-'0';isdigit(ch=getchar());x=x*10+ch-'0'); x*=flg;
}
const int MAXN = 100005;
const LL INF = 1e10;
int n, m, fir[MAXN], nxt[MAXN<<1], to[MAXN<<1], cnt; LL V[MAXN];
inline void link(int u, int v) {
	to[++cnt] = v; nxt[cnt] = fir[u]; fir[u] = cnt;
	to[++cnt] = u; nxt[cnt] = fir[v]; fir[v] = cnt;
}
int tmr, fa[MAXN], dfn[MAXN], tp[MAXN], bt[MAXN], son[MAXN], sz[MAXN], seq[MAXN];
struct mat {
	LL a[2][2];
	LL* operator[](int x) { return a[x]; }
	mat operator*(const mat &o)const {
		mat re;
		for(int i = 0; i < 2; ++i)
			for(int j = 0; j < 2; ++j)
				re.a[i][j] = min(a[i][0]+o.a[0][j], a[i][1]+o.a[1][j]);
		return re;
	}
}t[MAXN<<2], val[MAXN];
void dfs1(int u, int ff) {
	fa[u] = ff; sz[u] = 1;
	for(int i = fir[u], v; i; i = nxt[i])
		if((v=to[i]) != ff) {
			dfs1(v, u), sz[u] += sz[v];
			(sz[v] > sz[son[u]]) && (son[u] = v);
		}
}
LL f[MAXN][2];
void dfs2(int u, int top) {
	tp[u] = top; bt[top] = u;
	seq[dfn[u]=++tmr] = u;
	if(son[u]) dfs2(son[u], top);
	for(int i = fir[u], v; i; i = nxt[i])
		if((v=to[i]) != fa[u] && v != son[u])
			dfs2(v, v);
}
void dp(int u) {
	f[u][0] = V[u]; f[u][1] = 0;
	for(int i = fir[u], v; i; i = nxt[i])
		if((v=to[i]) != fa[u])
			dp(v),
			f[u][0] += min(f[v][0], f[v][1]),
			f[u][1] += f[v][0];
}
void build(int i, int l, int r) {
	if(l == r) {
		LL f0 = V[seq[l]], f1 = 0;
		for(int j = fir[seq[l]], v; j; j = nxt[j])
			if((v=to[j]) != fa[seq[l]] && v != son[seq[l]])
				f0 += min(f[v][0], f[v][1]),
				f1 += f[v][0];
		val[l] = t[i] = (mat){ {{f0, f0} , {f1, INF}} };
		return;
	}
	int mid = (l + r) >> 1;
	build(i<<1, l, mid);
	build(i<<1|1, mid+1, r);
	t[i] = t[i<<1] * t[i<<1|1];
}
void update(int i, int l, int r, int x) {
	if(l == r) { t[i] = val[l]; return; }
	int mid = (l + r) >> 1;
	if(x <= mid) update(i<<1, l, mid, x);
	else update(i<<1|1, mid+1, r, x);
	t[i] = t[i<<1] * t[i<<1|1];
}
mat query(int i, int l, int r, int x, int y) {
	if(x == l && r == y) return t[i];
	int mid = (l + r) >> 1;
	if(y <= mid) return query(i<<1, l, mid, x, y);
	if(x > mid) return query(i<<1|1, mid+1, r, x, y);
	return query(i<<1, l, mid, x, mid) * query(i<<1|1, mid+1, r, mid+1, y);
}
void modify(int u, LL W) {
	val[dfn[u]][0][0] += W-V[u];
	val[dfn[u]][0][1] += W-V[u];
	V[u]=W;
	while(u) {
		mat pre = query(1, 1, n, dfn[tp[u]], dfn[bt[tp[u]]]);
		update(1, 1, n, dfn[u]);
		mat now = query(1, 1, n, dfn[tp[u]], dfn[bt[tp[u]]]);
		u = fa[tp[u]]; if(!u) return; int x = dfn[u];
		LL p0 = pre[0][0], p1 = pre[1][0];
		LL n0 = now[0][0], n1 = now[1][0];
		val[x][0][0] = val[x][0][1] = val[x][0][0] + min(n0, n1) - min(p0, p1);
		val[x][1][0] = val[x][1][0] + n0 - p0;
	}
}
map<pair<int,int>, bool>E;
char s[10];
int main () {
	read(n), read(m); scanf("%s", s);
	for(int i = 1; i <= n; ++i) read(V[i]);
	for(int i = 1, u, v; i < n; ++i) read(u), read(v), link(u, v), E[pair<int,int>(min(u,v), max(u,v))] = 1;
	dfs1(1, 0), dfs2(1, 1), dp(1);
	build(1, 1, n);
	int a, x, b, y;
	while(m--) {
		read(a), read(x), read(b), read(y);
		if(!x && !y && E.count(pair<int,int>(min(a,b), max(a,b)))) {
			puts("-1"); continue;
		}
		LL sum = 0;
		LL tmpa = V[a]; modify(a, V[a] + (x ? -INF : INF)); sum += (x ? -INF : 0);
		LL tmpb = V[b]; modify(b, V[b] + (y ? -INF : INF)); sum += (y ? -INF : 0);
		mat ans = query(1, 1, n, 1, dfn[bt[1]]);
		printf("%lld\n", min(ans[0][0], ans[1][0])-sum);
		modify(a, tmpa), modify(b, tmpb);
	}
}
发布了367 篇原创文章 · 获赞 239 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/Ike940067893/article/details/102825052