【洛谷P4719】动态dp

Description

给定一棵树,点带点权,允许修改点权,求每次修改之后树的最大独立集

Solution

ddp用LCT维护

前置知识(静态树的最大独立集问题)

首先,我们要明确静态树的最大独立集的解法

定义$f[i][0/1]$表示在以$i$为根的子树中,该节点选/不选的最大权值,那么有状态转移方程

$$\left\{
\begin{matrix}
f[i][0]=\sum\limits_{j\in son(i)}{max\{f[j][0],f[j][1]\}} \\
f[i][1]=val[i]+\sum\limits_{j\in son(i)}{f[j][0]}
\end{matrix}
\right.
$$

我们可以通过一遍dfs在$O(n)$的时间内求出

简化版问题

假定现在这道题不是一棵树而是一个序列,允许修改点权,并且要求求出若干个两两不相邻的点的最大权值和

状态定义类似:定义$f[i][0/1]$表示在前$i$个元素中,$i$选/不选的最大权值,那么有状态转移方程

$$\left\{
\begin{matrix}
f[i][0]=max\{f[i-1][1],f[i-1][0]\} \\
f[i][1]=val[i]+f[i-1][0]
\end{matrix}
\right.
$$

矩阵优化转移

我们将转移用矩阵进行优化,并且重新定义矩阵乘法的含义,假定$C=A\times B$,那么有

$$C_{i,j}=\max\limits_{k\in [1, j]}\{A_{i,k}+B_{k,j}\}$$

因此,转移可以写成这样

$$
\begin{bmatrix}
0 & 0 \\
val[i] & -\infty
\end{bmatrix}
\times
\begin{bmatrix}
f[i-1][0] \\
f[i-1][1]
\end{bmatrix}
=
\begin{bmatrix}
f[i][0] \\
f[i][1]
\end{bmatrix}
$$

所以我们转移时将这些矩阵乘起来就好了

可以用线段树维护,时间复杂度$O(mlogn)$

(真的)动态dp

现在我们把这个问题搬到了树上

再套一个LCT维护即可

我们定义状态,$g[i][1/0]$表示在以$i$为根的子树中,轻儿子及其子树的dp值,那么有状态转移方程

$$\left\{
\begin{matrix}
g[i][0]=\sum\limits_{j\in lightson(i)}{max\{f[j][0],f[j][1]\}} \\
g[i][1]=val[i]+\sum\limits_{j\in lightson(i)}{f[j][0]}
\end{matrix}
\right.
$$

同时,$f$也可以维护:

$$\left\{
\begin{matrix}
f[i][0]=g[i][0]+ \max\{f[i.heavyson][0],f[i.heavyson][1]\} \\
f[i][1]=g[i][1]+f[i.heavyson][0]
\end{matrix}
\right.
$$

同样用矩阵优化转移:

$$
\begin{bmatrix}
g[i][0] & g[i][0] \\
g[i][1] & -\infty
\end{bmatrix}
\times
\begin{bmatrix}
f[i.heavyson][0] \\
f[i.heavyson][1]
\end{bmatrix}
=
\begin{bmatrix}
f[i][0] \\
f[i][1]
\end{bmatrix}
$$

这样,我们用LCT就能维护这个dp了

时间复杂度为$O(mlogn)$

Code

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 typedef long long ll;
  4 const int N = 1e5 + 10;
  5 const int INF = 0x3f3f3f3f;
  6 inline int read() {
  7     int ret = 0, op = 1;
  8     char c = getchar();
  9     while (!isdigit(c)) {
 10         if (c == '-') op = -1; 
 11         c = getchar();
 12     }
 13     while (isdigit(c)) {
 14         ret = (ret << 3) + (ret << 1) + c - '0';
 15         c = getchar();
 16     }
 17     return ret * op;
 18 }
 19 struct Edge {
 20     int nxt, to;
 21 } e[N << 1];
 22 struct Matrix {
 23     int m[2][2];
 24     Matrix() {memset(m, 0, sizeof(m));}
 25     inline void build(int x, int y) {
 26         m[0][0] = m[0][1] = x;
 27         m[1][0] = y; m[1][1] = -INF;
 28     }
 29     inline int getmax() {
 30         return max(m[0][0], m[1][0]);
 31     }
 32     Matrix operator *(const Matrix &x) const {
 33         Matrix ret;
 34         for (register int i = 0; i < 2; ++i)
 35             for (register int j = 0; j < 2; ++j)
 36                 for (register int k = 0; k < 2; ++k)
 37                     ret.m[i][j] = max(ret.m[i][j], m[i][k] + x.m[k][j]);
 38         return ret; 
 39     }
 40 };
 41 struct LCT {
 42     int fa, ch[2], f[2];
 43     Matrix x;
 44 } a[N];
 45 int num, head[N], n, m, val[N];
 46 inline void add(int from, int to) {
 47     e[++num].nxt = head[from];
 48     e[num].to = to;
 49     head[from] = num;
 50 }
 51 void dfs(int now, int fa) {
 52     a[now].f[1] = val[now];
 53     for (register int i = head[now]; i; i = e[i].nxt) {
 54         int to = e[i].to;
 55         if (to == fa) continue ;
 56         a[to].fa = now;
 57         dfs(to, now);
 58         a[now].f[0] += max(a[to].f[0], a[to].f[1]);
 59         a[now].f[1] += a[to].f[0];
 60     }
 61     a[now].x.build(a[now].f[0], a[now].f[1]);
 62 }
 63 inline int isnroot(int now) {
 64     return a[a[now].fa].ch[1] == now || a[a[now].fa].ch[0] == now;
 65 }
 66 inline void update(int now) {
 67     a[now].x.build(a[now].f[0], a[now].f[1]);
 68     if (a[now].ch[0]) a[now].x = a[a[now].ch[0]].x * a[now].x;
 69     if (a[now].ch[1]) a[now].x = a[now].x * a[a[now].ch[1]].x;
 70 }
 71 inline void rotate(int x) {
 72     int y = a[x].fa;
 73     int z = a[y].fa;
 74     int xson = a[y].ch[1] == x;
 75     int yson = a[z].ch[1] == y;
 76     int B = a[x].ch[xson ^ 1];
 77     if (isnroot(y)) a[z].ch[yson] = x;
 78     a[y].ch[xson] = B;
 79     a[x].ch[xson ^ 1] = y;
 80     if (B) a[B].fa = y;
 81     a[y].fa = x;
 82     a[x].fa = z;
 83     update(y);
 84     update(x);
 85 }
 86 void splay(int x) {
 87     while (isnroot(x)) {
 88         int y = a[x].fa;
 89         int z = a[y].fa;
 90         if (isnroot(y))
 91             (a[y].ch[0] == x) ^ (a[z].ch[0] == y) ? rotate(x) : rotate(y); 
 92         rotate(x);
 93     }
 94     update(x);
 95 }
 96 void access(int x) {
 97     for (register int y = 0; x; y = x, x = a[x].fa) {
 98         splay(x);
 99         if (a[x].ch[1]) {
100             a[x].f[0] += a[a[x].ch[1]].x.getmax();
101             a[x].f[1] += a[a[x].ch[1]].x.m[0][0];
102         }
103         if (y) {
104             a[x].f[0] -= a[y].x.getmax();
105             a[x].f[1] -= a[y].x.m[0][0];
106         }
107         a[x].ch[1] = y;
108         update(x);
109     }
110 }
111 int main() {
112     n = read(); m = read();
113     for (register int i = 1; i <= n; ++i) val[i] = read();
114     for (register int i = 1; i < n; ++i) {
115         int x = read(), y = read();
116         add(x, y); add(y, x);
117     }
118     dfs(1, 0);
119     while (m--) {
120         int x = read();
121         int y = read();
122         access(x);
123         splay(x);
124         a[x].f[1] += y - val[x];
125         val[x] = y;
126         update(x);
127         splay(1);
128         printf("%d\n", a[1].x.getmax());
129     }
130     return 0;
131 }
AC Code

 

posted @ 2019-08-16 17:37  AD_shl  阅读(331)  评论(0编辑  收藏  举报