[jzoj]5966. 【NOIP2018提高组D2T3】保卫王国(矩阵乘法+链剖维护线段树 或 倍增DP)

版权声明:蒟蒻写的文章,能看就行了,同时欢迎大佬们指点错误 https://blog.csdn.net/Algor_pro_king_John/article/details/84190870

Problem

  • 弱化版动态询问一棵树的最小覆盖集.

  • 每次只选择其中某两个点必选或必不选,且询问独立.

Data constraint

  • n , m 1 0 5 n,m\le 10^5

Solution

【动态DP = 树链剖分 + 线段树 + 矩阵转移】
  • 这好像是 W C 2018 WC_{2018} 搞出来的一个新玩意儿,挺神奇的.

  • 首先,最小覆盖集 = 全集 - 最大独立集.

  • 其次,一个点必选或不必选,可以直接把他的权值赋值为无穷大,或无穷小.

  • 这样,问题完美转化为求解一棵树的最大独立集.

  • 一个小学四年级的DP是 f [ i ] [ 0 / 1 ] f[i][0/1] 表示 i i 点选或不选,最大收益.

  • 先树剖一下,然后一个初三的DP是,设一个 g [ i ] [ 0 / 1 ] g[i][0/1] 表示与 f f 含义相同,唯独不能用重儿子去转移.

  • 这样有什么好处?

  • 我们不妨用 i i 表示当前要计算 f f 的点,假设它在线段树上的编号也是 i i ,那么它的重儿子在线段树上的编号就是 i + 1 i+1 .

  • 那么你可以写出这样的两条式子: f [ i ] [ 0 ] = g [ i ] [ 0 ] + m a x ( f [ i + 1 ] [ 0 ] , f [ i + 1 ] [ 1 ] ) f[i][0] = g[i][0] + max(f[i+1][0], f[i+1][1]) f [ i ] [ 1 ] = g [ i ] [ 1 ] + f [ i + 1 ] [ 0 ] f[i][1] = g[i][1] + f[i+1][0] .

  • 然后神奇的一步出现,你考虑把它写成矩阵转移的形式,会变成: [ g i , 0 g i , 0 g i , 1 0 ] [ f i + 1 , 0 f i + 1 , 1 ] = [ f i , 0 f i , 1 ] \begin{bmatrix}g_{i, 0} & g_{i, 0} \\g_{i, 1} & 0\end{bmatrix} * \begin{bmatrix}f_{i + 1, 0} \\ f_{i + 1, 1}\end{bmatrix} = \begin{bmatrix}f_{i, 0} \\ f_{i, 1}\end{bmatrix}

  • 这里需要注意,普通的矩阵乘法形式是形如: C i , j = k = 1 n A i , k B k , j C_{i, j} = \sum_{k = 1}^{n} A_{i, k} * B_{k, j}

  • 而这里,我们把它改变一下,变成 C i , j = max k = 1 n ( A i , k + B k , j ) C_{i, j} = \max_{k = 1}^{n} (A_{i, k} + B_{k, j})

  • 并且发现后者也是满足所谓的结合律的.

  • 那么不难发现,其实一个点的答案,就是它所在重链的每一个节点的g矩阵乘起来.

  • 因为满足结合律,所以刚好可以用链剖+线段树来维护.

  • 然后考虑修改,假设修改一个点 x x 的权值,那么其实父亲 g g 矩阵不会改变,I.e.其所在重链的所有祖先的 g g 矩阵不会改变.

  • 会改变的仅仅是 x x 本身的 g g 矩阵,以及所在重链每一个祖先的 f f 值(答案).

  • 因为会影响祖先的 f f 值,所以在经过完这条重链后走一条轻边到达另一条重链时,会影响到那条链上的 g g 矩阵.

  • 所以我们的修改步骤就很明确了:

    • 先修改当前权值,然后处理一下 g g 矩阵.

    • 然后进入循环,一直向顶端去修改.

  • 具体实现的时候,实际上我们可以记录一个 b [ x ] b[x] 表示 x x 这个点在线段树上的编号.

  • 那么修改一个点的 g g 矩阵直接修改即可,然后暴力的往上跳,进行合并即可.

  • 这样常数会小很多,且可以优化一下这个转移,把它不要真的写成取max,这样太慢.

  • 参考代码:

#include <cstdio>
#include <cstring>
#include <iostream>

#define ll long long
#define F(i, a, b) for (ll i = a; i <= b; i ++)
#define max(a, b) ((a) > (b) ? (a) : (b))
#define mem(a, b) memset(a, b, sizeof a)
#define mec(a, b) memcpy(a, b, sizeof a)
#define mx(a, b) ((a) = max(a, b))
#define get getchar()

#define M (st + en >> 1)
#define Ls (x << 1)
#define Rs (Ls | 1)

const ll N = 2e5 + 10, T = 4 * N, W = 1e15;

using namespace std;

ll n, m, u, v, a, x, b, y, t, cnt, Sum, sum, DFN[N], V[N]; char ch[10];
ll sz[N], fa[N], Son[N], top[N], dfn[N], f[N][2], B[N], D[N];
ll tov[T], nex[T], las[N], tot, S0, S1;

struct mat {
	ll g[2][2];
	mat() { mem(g, 0); }
	inline mat operator * (const mat &b) const { mat c;
		c.g[0][0] = max(g[0][0] + b.g[0][0], g[0][1] + b.g[1][0]);
		c.g[0][1] = max(g[0][0] + b.g[0][1], g[0][1] + b.g[1][1]);
		c.g[1][0] = max(g[1][0] + b.g[0][0], g[1][1] + b.g[1][0]);
		c.g[1][1] = max(g[1][0] + b.g[0][1], g[1][1] + b.g[1][1]);
		return c;
	}
} tr[T], TR[T], ANS, LAS, NOW, PRE, SON;

inline void Re(ll &x) {
	char c = get; x = 0; ll t = 1;
	for (; !isdigit(c); c = get) t = (c == '-' ? - 1 : t);
	for (; isdigit(c); x = (x << 3) + (x << 1) + c - '0', c = get); x *= t;
}
inline void Wr(ll x) {
	if (x < 0) { putchar('-'); x = - x;	}
	if (x > 9) Wr(x / 10); putchar(x % 10 + '0');
}

void ins(ll x, ll y) { tov[++ tot] = y, nex[tot] = las[x], las[x] = tot;}
void Dfs(ll k) {
	sz[k] ++;
	for (ll x= las[k], Hv = 0; x ; x = nex[x])
		if (!sz[tov[x]]) fa[tov[x]] = k, Dfs(tov[x]), Son[k] = sz[tov[x]] > Hv ? tov[x] : Son[k], mx(Hv, sz[tov[x]]), sz[k] += sz[tov[x]];
}
void Dfn(ll k) {
	dfn[k] = DFN[k] = ++ cnt;
	if (Son[k]) top[Son[k]] = top[k], Dfn(Son[k]), DFN[k] = DFN[Son[k]];
	for (ll x = las[k] ; x ; x = nex[x])
		if (tov[x] ^ Son[k] && sz[tov[x]] < sz[k])
			top[tov[x]] = tov[x], Dfn(tov[x]);
}

void Modify(ll x, ll st, ll en, ll p) {
	if (st == en) B[st] = x;
		else
	M >= dfn[p] ? Modify(Ls, st, M, p) : Modify(Rs, M + 1, en, p);
}
void Down(int x) { for (; x > 1 ; x >>= 1, tr[x] = tr[Ls] * tr[Rs]); }

void DP(ll k) {
	for (ll x = las[k] ; x ; x = nex[x])
		if (sz[k] > sz[tov[x]]) DP(tov[x]);
	for (ll x = las[k], y; x ; x = nex[x])
		if (sz[k] > sz[y = tov[x]]) {
			f[k][0] += max(f[y][0], f[y][1]);
			f[k][1] += f[y][0];
		}
	f[k][1] += V[k];

	tr[B[dfn[k]]].g[0][0] = tr[B[dfn[k]]].g[0][1] = f[k][0] - max(f[Son[k]][0], f[Son[k]][1]);
	tr[B[dfn[k]]].g[1][0] = f[k][1] - f[Son[k]][0], tr[B[dfn[k]]].g[1][1] = - W;

	Down(B[dfn[k]]);
}

mat Query(ll x, ll st, ll en, ll l, ll r) {
	if (l <= st && en <= r) return tr[x];
	if (r <= M) return Query(Ls, st, M, l, r);
	if (l > M) return Query(Rs, M + 1, en, l, r);
	return Query(Ls, st, M, l, r) * Query(Rs, M + 1, en, l, r);
}

void Update(ll x, ll y) {
	LAS = Query(1, 1, n, dfn[top[x]], DFN[top[x]]), tr[B[dfn[x]]].g[1][0] += y;
	Down(B[dfn[x]]), D[++ D[0]] = x;
	while (fa[top[x]]) {
		ANS = Query(1, 1, n, dfn[top[x]], DFN[top[x]]); t = top[x], x = fa[t];
		if (top[x]) PRE = Query(1, 1, n, dfn[top[x]], DFN[top[x]]);
		NOW = Query(1, 1, n, dfn[x], DFN[x]);
		SON = Query(1, 1, n, dfn[Son[x]], DFN[Son[x]]);
		tr[B[dfn[x]]].g[0][0] = tr[B[dfn[x]]].g[0][1] =
			NOW.g[0][0] - max(SON.g[0][0], SON.g[1][0]) - max(LAS.g[0][0], LAS.g[1][0]) + max(ANS.g[0][0], ANS.g[1][0]);
		tr[B[dfn[x]]].g[1][0] =
			NOW.g[1][0] - SON.g[0][0] - LAS.g[0][0] + ANS.g[0][0];
		Down(B[dfn[x]]), LAS = PRE, D[++ D[0]] = x;
	}
}

int main() {
	freopen("defense.in", "r", stdin);
	freopen("defense.out", "w", stdout);

	Re(n), Re(m); scanf("%s", ch + 1);
	F(i, 1, n) Re(V[i]), sum += V[i];
	F(i, 1, n - 1) Re(u), Re(v), ins(u, v), ins(v, u);

	Dfs(1), top[1] = 1, Dfn(1);
	F(i, 1, n) Modify(1, 1, n, i);
	DP(1), mec(TR, tr);

 	F(i, 1, m) {
		Re(a), Re(x), Re(b), Re(y), Sum = 0, D[0] = 0;
		if ((fa[a] == b || fa[b] == a) && x + y == 0) { puts("-1"); continue; }
		if (x == 0) Update(a, W), Sum += W; else Update(a, - W);
		if (y == 0) Update(b, W), Sum += W; else Update(b, - W);
		ANS = Query(1, 1, n, 1, DFN[1]), Wr(sum - (max(ANS.g[0][0], ANS.g[1][0]) - Sum)), putchar('\n');
		F(i, 1, D[0]) tr[B[dfn[D[i]]]] = TR[B[dfn[D[i]]]], Down(B[dfn[D[i]]]);
	}
}

【倍增DP】
  • 待学

猜你喜欢

转载自blog.csdn.net/Algor_pro_king_John/article/details/84190870