(大佬勿喷)
(请不要嘲笑我讲得不清楚,因为我太菜了。。。)
(请不要嘲笑我看了题解再写题解,因为我实在是太菜了。。。)
令 d p [ x ] [ 0 ] dp[x][0] dp[x][0] 为以 x x x 为根不选 x x x 的最大权独立集的大小。
令 d p [ x ] [ 1 ] dp[x][1] dp[x][1] 为以 x x x 为根选 x x x 的最大权独立集的大小。
令 y y y 的 x x x 的子节点。
这题可以很容易写出dp式:
d p [ x ] [ 0 ] = ∑ m a x ( d p [ y ] [ 0 ] , d p [ y ] [ 1 ] ) dp[x][0]=\sum {max(dp[y][0],dp[y][1])} dp[x][0]=∑max(dp[y][0],dp[y][1])
d p [ x ] [ 1 ] = a [ x ] + ∑ d p [ y ] [ 0 ] dp[x][1]=a[x]+\sum dp[y][0] dp[x][1]=a[x]+∑dp[y][0]
a [ x ] a[x] a[x] 即为 x x x 的权值,最后的答案是 m a x ( d p [ x ] [ 0 ] , d p [ x ] [ 1 ] ) max(dp[x][0],dp[x][1]) max(dp[x][0],dp[x][1])。
若暴力修改,时间复杂度 O ( n m ) O(nm) O(nm)。
当然,很容易会发现,我们只用修改从要修改的点到根节点(这里设为 1 1 1)路径上的点即可。
稍微改一下,时间复杂度 O ( m d ) O(md) O(md)(其中 d d d 为深度)
进入正题。不妨看看刚才我说了啥。
我们只用修改从要修改的点到根节点(这里设为 1 1 1)路径上的点即可。
ok,相信聪明的你已经想到了树链剖分。(听说可以用什么全局平衡二叉树做的,但我太菜了不会。。。)
那重链中怎么更新呢?我们定义 s o n son son 为点 x x x 的重儿子。
再看看这个式子。
d p [ x ] [ 0 ] = ∑ m a x ( d p [ y ] [ 0 ] , d p [ y ] [ 1 ] ) dp[x][0]=\sum {max(dp[y][0],dp[y][1])} dp[x][0]=∑max(dp[y][0],dp[y][1])
d p [ x ] [ 1 ] = a [ x ] + ∑ d p [ y ] [ 0 ] dp[x][1]=a[x]+\sum dp[y][0] dp[x][1]=a[x]+∑dp[y][0]
看着 ∑ \sum ∑ 不爽,而且便于用到 s o n son son 变量,不妨把轻儿子都拣出来,再添加一个概念。
定义 f [ x ] [ 1 ] f[x][1] f[x][1] 为 x x x 的所有轻儿子都不选,再选 x x x 最大权独立集的大小,定义 f [ x ] [ 0 ] f[x][0] f[x][0] 为所有的轻儿子可选可不选,不选 x x x 的最大权独立集的大小。
则 d p [ x ] [ 0 ] = f [ x ] [ 0 ] + max ( d p [ s o n ] [ 0 ] , d p [ s o n ] [ 1 ] ) dp[x][0]=f[x][0]+\max(dp[son][0],dp[son][1]) dp[x][0]=f[x][0]+max(dp[son][0],dp[son][1])
d p [ x ] [ 1 ] = f [ x ] [ 1 ] + d p [ s o n ] [ 0 ] dp[x][1]=f[x][1]+dp[son][0] dp[x][1]=f[x][1]+dp[son][0]
我们不妨把转移写成矩阵的形式。你会问了,这明明就不像矩乘呀,别慌,定义一个新的运算符 × \times ×,对于矩阵 A 、 B A、B A、B,定义 C C C 为 A × B A\times B A×B,则 C [ i ] [ j ] = max k { A [ i ] [ k ] + B [ k ] [ j ] } C[i][j]=\max_k\{A[i][k]+B[k][j]\} C[i][j]=maxk{A[i][k]+B[k][j]}(注意这个也是满足矩阵结合律的)
再换一下dp式
则 d p [ x ] [ 0 ] = max ( f [ x ] [ 0 ] + d p [ s o n ] [ 0 ] , f [ x ] [ 0 ] + d p [ s o n ] [ 1 ] ) dp[x][0]=\max(f[x][0]+dp[son][0],f[x][0]+dp[son][1]) dp[x][0]=max(f[x][0]+dp[son][0],f[x][0]+dp[son][1])
d p [ x ] [ 1 ] = m a x ( f [ x ] [ 1 ] + d p [ s o n ] [ 0 ] , − ∞ ) dp[x][1]=max(f[x][1]+dp[son][0],-\infty) dp[x][1]=max(f[x][1]+dp[son][0],−∞)
推一推,发现
[
d
p
[
s
o
n
]
[
0
]
d
p
[
s
o
n
]
[
1
]
]
∗
[
f
[
x
]
[
0
]
f
[
x
]
[
1
]
f
[
x
]
[
0
]
−
∞
]
=
[
d
p
[
x
]
[
0
]
d
p
[
x
]
[
1
]
]
\left[ \begin{matrix} dp[son][0] & dp[son][1] \end{matrix}\right] * \left[\begin{matrix} f[x][0]&f[x][1]\\f[x][0]& -\infty\end{matrix}\right]=\left[ \begin{matrix} dp[x][0]&dp[x][1] \end{matrix}\right]
[dp[son][0]dp[son][1]]∗[f[x][0]f[x][0]f[x][1]−∞]=[dp[x][0]dp[x][1]]
注意这里的
d
p
dp
dp 矩阵是横着的。(根据我算矩阵的习惯来说必须这样)
对于此时,查询答案的话在线段树上跑,将所有元素乘起来再乘 [ 0 , − ∞ ] [0,-\infty] [0,−∞] 即可,时间复杂度: O ( l o g 2 ( n ) ) O(log^2(n)) O(log2(n))。
修改的话就像树剖那样,改每条链即可(这里需要用上一条链的链顶改下一条链的链顶),时间复杂度: O ( l o g 2 ( n ) ) O(log^2(n)) O(log2(n))。
就是这样了,具体见代码吧。。。
总时间复杂度: O ( n l o g 2 ( n ) ) O(nlog^2(n)) O(nlog2(n))。
Code
再让我调一下。。。
只能明早做二分图了。。。
upd:放个代码,事实上,这篇文章是我初二写的,但是代码是三年后调对的。
现在再来看此文,觉得还是写的很清晰的。
/*
世界の果てさえ
【世界的尽头在何处】
仆らは知らない
【我们也无从知晓】
*/
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector>
#include <set>
#include <map>
#define pr pair <int, int>
#define mr make_pair
#define LL long long
#define ls tree[p].L
#define rs tree[p].R
using namespace std;
const int MAXN = 1e5 + 5, inf = 0x3f3f3f3f;
struct node {
LL s[2][2];
node() {
for(int i = 0; i <= 1; i ++) for(int j = 0; j <= 1; j ++) s[i][j] = -inf;
}
node operator * (const node P) const {
node ans;
for(int k = 0; k <= 1; k ++) {
for(int i = 0; i <= 1; i ++) {
for(int j = 0; j <= 1; j ++) ans.s[i][j] = max(ans.s[i][j], s[i][k] + P.s[k][j]);
}
}
return ans;
}
}mat1[MAXN];
struct sgt {
int L, R;
node mat;
}tree[MAXN << 2];
int n, m, a[MAXN], dfn[MAXN], mp[MAXN], son[MAXN];
int tot, d[MAXN], siz[MAXN], Fa[MAXN], tp[MAXN], ed[MAXN];
LL dp[MAXN][2];
vector <int> v[MAXN];
void read(int &x) {
x = 0; bool f = 1; char C = getchar();
for(; C < '0' || C > '9'; C = getchar()) if(C == '-') f = 0;
for(; C >= '0' && C <= '9'; C = getchar()) x = (x << 1) + (x << 3) + (C ^ 48);
x = (f ? x : -x);
}
void dfs(int x, int fa) {
siz[x] = 1; Fa[x] = fa; d[x] = d[fa] + 1; dp[x][1] = a[x]; dp[x][0] = 0;
for(auto y : v[x]) {
if(y == fa) continue;
dfs(y, x);
siz[x] += siz[y]; dp[x][0] += max(dp[y][0], dp[y][1]); dp[x][1] += dp[y][0];
if(siz[son[x]] < siz[y]) son[x] = y;
}
}
void dfs1(int x, int t) {
tp[x] = t; dfn[++ tot] = x; mp[x] = tot; mat1[x].s[0][1] = a[x]; mat1[x].s[1][1] = -inf;
mat1[x].s[0][0] = mat1[x].s[1][0] = 0;
ed[t] = tot;
if(son[x]) dfs1(son[x], t);
for(auto y : v[x]) {
if(y == son[x] || y == Fa[x]) continue;
dfs1(y, y); mat1[x].s[0][0] += max(dp[y][0], dp[y][1]); mat1[x].s[1][0] += max(dp[y][0], dp[y][1]);
mat1[x].s[0][1] += dp[y][0];
}
}
void build(int p, int l, int r) {
tree[p].L = l; tree[p].R = r;
if(l == r) {
tree[p].mat = mat1[dfn[l]];
// for(int i = 0; i <= 1; i ++) {
// for(int j = 0; j <= 1; j ++) {
// printf("%lld ", tree[p].mat.s[i][j]);
// }
// printf("\n");
// }
// printf("|%d|\n", l);
return;
}
int mid = (l + r) >> 1; build(p << 1, l, mid); build(p << 1 | 1, mid + 1, r);
tree[p].mat = tree[p << 1 | 1].mat * tree[p << 1].mat;
}
void cng(int p, int x) {
if(tree[p].L == tree[p].R) {
tree[p].mat = mat1[dfn[x]]; return;
}
int mid = (tree[p].L + tree[p].R) >> 1;
if(x <= mid) cng(p << 1, x);
else cng(p << 1 | 1, x);
tree[p].mat = tree[p << 1 | 1].mat * tree[p << 1].mat;
}
node ask(int p, int ql, int qr) {
if(tree[p].L >= ql && tree[p].R <= qr) return tree[p].mat;
int mid = (tree[p].L + tree[p].R) >> 1;
if(mid < ql) return ask(p << 1 | 1, ql, qr);
if(mid >= qr) return ask(p << 1, ql, qr);
node q = ask(p << 1, ql, qr), r = ask(p << 1 | 1, ql, qr);
return r * q;
}
void modify(int x, int y) {
mat1[x].s[0][1] += y - a[x]; a[x] = y;
while(x) {
node p = ask(1, mp[tp[x]], ed[tp[x]]); cng(1, mp[x]);
node q = ask(1, mp[tp[x]], ed[tp[x]]); x = Fa[tp[x]];
mat1[x].s[0][0] -= max(p.s[0][0], p.s[0][1]); mat1[x].s[0][0] += max(q.s[0][0], q.s[0][1]);
mat1[x].s[1][0] -= max(p.s[0][0], p.s[0][1]); mat1[x].s[1][0] += max(q.s[0][0], q.s[0][1]);
mat1[x].s[0][1] -= p.s[0][0]; mat1[x].s[0][1] += q.s[0][0];
}
}
int main() {
read(n); read(m); int x, y;
for(int i = 1; i <= n; i ++) read(a[i]);
for(int i = 1; i <= n - 1; i ++) {
read(x); read(y); v[x].emplace_back(y); v[y].emplace_back(x);
}
dfs(1, 0); dfs1(1, 1); build(1, 1, n);
for(int i = 1; i <= m; i ++) {
read(x); read(y); modify(x, y);
node t = ask(1, 1, ed[1]); printf("%lld\n", max(t.s[0][0], t.s[0][1]));
}
return 0;
}