版权声明:_ https://blog.csdn.net/lunch__/article/details/84728818
题意
- 给定一棵 个点的树,点带点权。有 次操作,每次操作给定 ,表示修改点 的权值为 ,你需要在每次操作之后求出这棵树的最大权独立集的权值大小。
为了做 学的这个鬼东西…
感觉理解起来有点点难,还是要多看几遍
首先我们这个题可以很简单写出一个方程
设
为不选
时
子树内的最大独立集
设
为选
时
子树内的最大独立集
我们转移到某一个儿子 的时候
那么有式子
代表剩余的其他儿子的 值之和
显然 的计算与 无关
我们重新定义矩阵乘法 为
再把转移写成矩阵的形式
那么我们就可以通过矩阵动态维护
了
我们首先进行树链剖分
令每个点的矩阵为从重儿子转移到自身的矩阵
那么我们每当对一个点进行修改的时候
它的实父亲的转移矩阵是不会有变化的
但是每条轻边会导致一个点的转移矩阵变化
那么我们可以用线段树快速查询出一个点的 值
再用它去更新它虚父亲的转移矩阵即可
其中改变是这样的
定义转移后的 值为
那么
总结一下就是先记下当前重链顶端的 值
再修改当前点的转移矩阵
然后就是求出当前重链顶端的 值
再更新与这条重链通过轻边相连的上一条重链
这样子复杂度是
Codes
#include <bits/stdc++.h>
#define pb push_back
#define inf (0x3f3f3f3f)
using namespace std;
const int N = 1e5 + 10;
struct Martix {
int a[2][2];
Martix() {a[0][0] = a[0][1] = a[1][0] = a[1][1] = -inf;}
Martix operator * (const Martix &T) const {
Martix res;
res.a[0][0] = max(a[0][0] + T.a[0][0], a[0][1] + T.a[1][0]);
res.a[0][1] = max(a[0][0] + T.a[0][1], a[0][1] + T.a[1][1]);
res.a[1][0] = max(a[1][0] + T.a[0][0], a[1][1] + T.a[1][0]);
res.a[1][1] = max(a[1][0] + T.a[0][1], a[1][1] + T.a[1][1]);
return res;
}
}g[N];
void P(Martix x) {
cout << x.a[0][0] << ' ' << x.a[0][1] << endl << x.a[1][0] << ' ' << x.a[1][1] << endl;
}
vector<int> G[N];
int n, m, a[N], f[N][2];
int size[N], fa[N], heavy[N];
int top[N], st[N], ed[N], rel[N], cnt;
void dfs1(int x) {
size[x] = 1, f[x][1] = a[x];
for (auto v : G[x]) if (!size[v]) {
fa[v] = x;
dfs1(v);
f[x][0] += max(f[v][0], f[v][1]);
f[x][1] += f[v][0];
size[x] += size[v];
if (size[v] > size[heavy[x]])
heavy[x] = v;
}
int s0 = f[x][0] - max(f[heavy[x]][0], f[heavy[x]][1]), s1 = f[x][1] - f[heavy[x]][0];
g[x].a[0][0] = g[x].a[1][0] = s0, g[x].a[0][1] = s1, g[x].a[1][1] = -inf;
}
void dfs2(int x, int ancestor) {
rel[st[x] = ed[top[x] = ancestor] = ++ cnt] = x;
if (heavy[x]) dfs2(heavy[x], ancestor);
for (auto v : G[x]) if (!top[v])
dfs2(v, v);
}
struct Segment_Tree {
#define mid ((l + r) >> 1)
#define ls (bh << 1)
#define rs (ls | 1)
#define lson ls, l, mid
#define rson rs, mid + 1, r
Martix S[N << 2];
void pushup(int bh) {
S[bh] = S[rs] * S[ls];
}
void build(int bh, int l, int r) {
if (l == r) S[bh] = g[rel[l]];
else build(lson), build(rson), pushup(bh);
}
void update(int bh, int l, int r, int x) {
if (l == r) S[bh] = g[rel[x]];
else {
if (x <= mid) update(lson, x);
else update(rson, x);
pushup(bh);
}
}
Martix query(int bh, int l, int r, int x, int y) {
if (x <= l && r <= y) return S[bh];
if (x > mid) return query(rson, x, y);
if (y <= mid) return query(lson, x, y);
return query(rson, x, y) * query(lson, x, y);
}
}T;
int modify(int x, int y) {
Martix lst, now;
while (x) {
int del0, del1;
if (y) del1 = y, del0 = y = 0;
else {
del0 = max(now.a[0][0], now.a[0][1]) - max(lst.a[0][0], lst.a[0][1]);
del1 = now.a[0][0] - lst.a[0][0];
}
lst = T.query(1, 1, n, st[top[x]], ed[top[x]]);
g[x].a[0][0] += del0, g[x].a[1][0] += del0, g[x].a[0][1] += del1;
T.update(1, 1, n, st[x]);
now = T.query(1, 1, n, st[top[x]], ed[top[x]]);
x = fa[top[x]];
}
return max(now.a[0][0], now.a[0][1]);
}
int main() {
//freopen("ddp.in", "r", stdin);
//freopen("ddp.out", "w", stdout);
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++ i)
scanf("%d", &a[i]);
for (int x, y, i = 1; i < n; ++ i) {
scanf("%d%d", &x, &y);
G[x].pb(y), G[y].pb(x);
}
dfs1(1), dfs2(1, 1), T.build(1, 1, n);
//P(T.query(1, 1, n, st[1], ed[1]));
//cout << max(f[1][0], f[1][1]) << endl;
for (int x, y; m -- ; ) {
scanf("%d%d", &x, &y);
if (y == a[x]) {
Martix res = T.query(1, 1, n, st[1], ed[1]);
printf("%d\n", max(res.a[0][0], res.a[0][1]));
}
else printf("%d\n", modify(x, y - a[x])), a[x] = y;
}
return 0;
}
最后感谢这位大佬博客的指导