题目
分析
记 f u f_u fu 为 u u u 子树的答案, v v v 是 u u u 的儿子,则 f u = max { ∑ u f v , a u } f_u = \max\left\{\sum_{u}f_v, a_u\right\} fu=max{u∑fv,au} 接下来的过程与 【模板】“动态 DP“&动态树分治 几乎一致,找到转移方程的矩阵形式: ( g u a u − ∞ 0 ) × ( f h 0 ) = ( f u 0 ) \begin{pmatrix}g_u & a_u \\ -\infty & 0\end{pmatrix} \times \begin{pmatrix}f_h \\ 0\end{pmatrix} = \begin{pmatrix}f_u \\ 0\end{pmatrix} (gu−∞au0)×(fh0)=(fu0) 其中 h h h 是 u u u 的重儿子, g u = ∑ v ≠ h f v g_u = \sum_{v \neq h} f_v gu=∑v=hfv。乘法定义同样是 + → max , × → + + \to \max, \times \to + +→max,×→+。
值得一提的是,转移方程似乎可以写成 ( g u a u ) × ( f h ) = ( f u ) \begin{pmatrix}g_u & a_u\end{pmatrix} \times \begin{pmatrix}f_h\end{pmatrix} = \begin{pmatrix}f_u\end{pmatrix} (guau)×(fh)=(fu) 但是这样虽然意义上是合法的,但转移矩阵 ( g u a u ) \begin{pmatrix}g_u & a_u\end{pmatrix} (guau) 不是一个 n × n n \times n n×n 的矩阵,所以无法用线段树维护。
代码
好像需要氧气
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
typedef long long LL;
const int MAXN = 200000;
const LL INF = 1ll << 60;
struct Matrix {
LL Mat[2][2];
Matrix() {
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
Mat[i][j] = INF;
}
LL* operator [] (const int &i) {
return Mat[i];
}
Matrix operator * (Matrix other) {
Matrix ret;
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
for (int k = 0; k < 2; k++)
ret[i][j] = std::min(ret[i][j], Mat[i][k] + other[k][j]);
return ret;
}
void Debug() {
puts("");
for (int i = 0; i < 2; i++) {
printf("[");
for (int j = 0; j < 2; j++) {
if (Mat[i][j] >= INF)
printf("INF");
else
printf("%lld", Mat[i][j]);
if (j != 1)
putchar('\t');
}
printf("]\n");
}
puts("");
}
}H[MAXN + 5];
int N, Q;
int A[MAXN + 5];
std::vector<int> G[MAXN + 5];
int Fa[MAXN + 5], Size[MAXN + 5], Son[MAXN + 5];
int Top[MAXN + 5], Tid[MAXN + 5], Dfn[MAXN + 5], End[MAXN + 5], DfnCnt;
struct SegmentTree {
#define lch (u << 1)
#define rch (u << 1 | 1)
Matrix Mat[(MAXN << 2) + 5];
void PushUp(int u) {
Mat[u] = Mat[lch] * Mat[rch];
}
void Build(int u, int lft, int rgt) {
if (lft == rgt) {
Mat[u] = H[Tid[lft]];
// printf("Build{%d %d}", lft, rgt);
// Mat[u].Debug();
return;
}
int mid = (lft + rgt) >> 1;
Build(lch, lft, mid);
Build(rch, mid + 1, rgt);
PushUp(u);
}
void Modify(int u, int lft, int rgt, int pos) {
if (lft == rgt) {
Mat[u] = H[Tid[pos]];
return;
}
int mid = (lft + rgt) >> 1;
if (pos <= mid) Modify(lch, lft, mid, pos);
else Modify(rch, mid + 1, rgt, pos);
PushUp(u);
}
Matrix Query(int u, int lft, int rgt, int l, int r) {
if (l <= lft && rgt <= r) {
// printf("Query{%d %d}", lft, rgt);
// Mat[u].Debug();
return Mat[u];
}
int mid = (lft + rgt) >> 1;
if (l > mid) return Query(rch, mid + 1, rgt, l, r);
if (r <= mid) return Query(lch, lft, mid, l, r);
return Query(lch, lft, mid, l, r) * Query(rch, mid + 1, rgt, l, r);
}
#undef lch
#undef rch
}T;
void Dfs(int u, int fa) {
int Max = 0;
Fa[u] = fa, Size[u] = 1;
for (int i = 0; i < int(G[u].size()); i++) {
int v = G[u][i];
if (v != fa) {
Dfs(v, u);
Size[u] += Size[v];
if (Size[v] > Max)
Max = Size[Son[u] = v];
}
}
}
LL DpF[MAXN + 5], DpG[MAXN + 5];
void Dfs(int u, int fa, int top) {
Top[Tid[Dfn[u] = ++DfnCnt] = u] = top, End[top] = Dfn[u];
if (Son[u]) Dfs(Son[u], u, top);
else DpG[u] = INF;
for (int i = 0; i < int(G[u].size()); i++) {
int v = G[u][i];
if (v != fa && v != Son[u]) {
Dfs(v, u, v);
DpG[u] += DpF[v];
}
}
DpF[u] = std::min(DpG[u] + DpF[Son[u]], (LL)A[u]);
H[u][0][0] = DpG[u], H[u][0][1] = A[u];
H[u][1][0] = INF, H[u][1][1] = 0;
// printf("%d: %lld %lld", u, DpF[u], DpG[u]);
// H[u].Debug();
}
void Modify(int u, int d) {
H[u][0][1] += d;
while (u) {
Matrix X = T.Query(1, 1, N, Dfn[Top[u]], End[Top[u]]);
T.Modify(1, 1, N, Dfn[u]);
Matrix Y = T.Query(1, 1, N, Dfn[Top[u]], End[Top[u]]);
u = Fa[Top[u]];
H[u][0][0] += std::min(Y[0][0], Y[0][1]) - std::min(X[0][0], X[0][1]);
}
}
LL Query(int u) {
// printf("Query: [%d, %d]\n", Dfn[u], End[Top[u]]);
Matrix Ans = T.Query(1, 1, N, Dfn[u], End[Top[u]]);
// Ans.Debug();
return std::min(Ans[0][0], Ans[0][1]);
}
int main() {
scanf("%d", &N);
for (int i = 1; i <= N; i++)
scanf("%d", &A[i]);
for (int i = 1; i < N; i++) {
int u, v; scanf("%d%d", &u, &v);
G[u].push_back(v), G[v].push_back(u);
}
Dfs(1, 0);
Dfs(1, 0, 1);
T.Build(1, 1, N);
// for (int i = 1; i <= N; i++)
// printf("Dfn[%d] = %d, Tid[%d] = %d\n", i, Dfn[i], i, Tid[i]);
scanf("%d", &Q);
while (Q--) {
char opt[3]; scanf("%s", opt);
if (opt[0] == 'Q') {
int u; scanf("%d", &u);
printf("%lld\n", Query(u));
}
else {
int u, d; scanf("%d%d", &u, &d);
Modify(u, d);
}
}
return 0;
}