RT,样例第 5、6 行错误
// clang-format off
#include<bits/stdc++.h>
#include <cassert>
using namespace std;
#define il inline
#define mkp make_pair
#define pii pair<int,int>
#define pll pair<long long, long long>
#define fi first
#define se second
#define lll __int128
#define ll long long
#define db double
#define ldb long_double
#define sq(x) ((x)*(x))
#define For(i,j,k) for(int (i)=(j); (i)<=(k); ++(i))
#define ForDown(i,j,k) for(int (i)=(j); (i)>=(k); --(i))
#define pb push_back
#define FileIO(filename) freopen(filename ".in" ,"r",stdin);freopen(filename ".out" ,"w",stdout)
template<typename T> il void read(T &x){ x=0;int f=1;int c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)){x=x*10+c-'0';c=getchar();}x*=f;}
template<typename T, typename ... Args> il void read(T &x, Args &... y){ read(x);read(y...); }
template<typename T> il constexpr T qpow(T x, ll y, T mod=numeric_limits<int>::max()){T ans=1;x%=mod;while(y){if(y&1)(ans*=x)%=mod;(x*=x)%=mod;y>>=1;}return ans;}
#ifndef ONLINE_JUDGE
#define __lg log2
namespace _Debug {
template <typename T> inline void _debug(const char* format, T t) { cerr<<format<<'='<<t<<endl; }
template <class First, class... Rest> inline void _debug(const char* format, First first, Rest... rest) { while (*format != ',') cerr << *format++; cerr << '=' << first << ","; _debug(format + 1, rest...);}
template <typename T> ostream& operator<<(ostream& os, const vector<T>& V) { os << "[ "; for (const auto& vv : V) os << vv << ", "; os << "]"; return os; }
#define debug(...) cerr<<"Line "<<__LINE__<<": ",_debug(#__VA_ARGS__, __VA_ARGS__);
};
using namespace _Debug;
#endif
// File head end
// clang-format on
constexpr int MAXN = 1e5 + 5;
int n, Q, cnt = 0, a[MAXN], sz[MAXN], fa[MAXN], dep[MAXN], top[MAXN],
hson[MAXN], ed[MAXN], id[MAXN], dfn[MAXN], f[MAXN][2], g[MAXN][2];
vector<int> T[MAXN];
struct Matrix { // 矩阵
int a[2][2], n = 2, m = 2;
Matrix() { a[0][0] = a[0][1] = a[1][0] = 0, a[1][1] = -1e9; }
Matrix operator*(const Matrix &rhs) const {
Matrix res;
For(i, 0, 1) For(j, 0, 1) For(k, 0, 1) res.a[i][j] =
max(res.a[i][j], a[i][k] + rhs.a[k][j]);
return res;
}
int &operator[](const pii id) { return a[id.fi][id.se]; } // 下标访问
};
namespace SegmentTree { // 线段树
struct Node {
int l, r;
Matrix val;
} T[MAXN << 2];
int segtPtr[MAXN]; // 记录每个点真实编号(非 dfs 序)在线段树里的下标
#define lc(p) ((p) << 1)
#define rc(p) ((p) << 1 | 1)
#define pushUp(p) T[(p)].val = T[lc(p)].val * T[rc(p)].val
il void build(int p, int l, int r) {
T[p].l = l, T[p].r = r;
if (l == r) {
int ptr = dfn[l];
// cerr << ptr << endl;
segtPtr[ptr] = p;
if (!hson[ptr]) { // leaf
T[p].val[{0, 0}] = f[ptr][0];
T[p].val[{1, 0}] = f[ptr][1];
} else { // non-leaf
T[p].val[{0, 0}] = g[ptr][0];
T[p].val[{0, 1}] = g[ptr][0];
T[p].val[{1, 0}] = g[ptr][1];
T[p].val[{1, 1}] = -1e9;
}
return;
}
int mid = (l + r) >> 1;
build(lc(p), l, mid);
build(rc(p), mid + 1, r);
pushUp(p);
}
il Matrix qry(int p, int ql, int qr) { // 正常的询问区间「广义」乘
if (p == 1)
cerr << dfn[ql] << ' ' << dfn[qr] << endl;
int l = T[p].l, r = T[p].r;
if (ql <= l && qr >= r)
return T[p].val;
int mid = (l + r) >> 1;
if (ql <= mid && qr <= mid)
return qry(lc(p), ql, qr);
else if (ql > mid && qr > mid)
return qry(rc(p), ql, qr);
else if (ql <= mid && qr > mid)
return qry(lc(p), ql, qr) * qry(rc(p), ql, qr);
else
assert(0);
}
il void upd(int p) { // 向上维护
if (T[p].l == T[p].r)
p >>= 1;
while (p)
pushUp(p), p >>= 1;
}
} // namespace SegmentTree
void dfs1(int x, int pre) { // 树剖 dfs1
sz[x] = 1, hson[x] = 0, fa[x] = pre, dep[x] = dep[pre] + 1;
for (int v : T[x]) {
if (v == pre)
continue;
dfs1(v, x);
sz[v] += sz[x], hson[x] = sz[v] > sz[hson[x]] ? v : hson[x];
// hson 是重孩子
}
}
void dfs2(int x, int tp) { // 树剖 dfs2
id[x] = ++cnt, dfn[cnt] = x, g[x][1] = a[x], g[x][0] = 0,
f[x][1] = f[x][0] = 0, top[x] = tp, ed[tp] = max(ed[tp], cnt);
if (!hson[x]) // 叶子结点
return f[x][1] = a[x], void();
dfs2(hson[x], tp);
for (int v : T[x]) {
if (v == fa[x] || v == hson[x])
continue;
dfs2(v, v);
g[x][1] += f[v][0], g[x][0] += max(f[v][1], f[v][0]);
}
f[x][0] = max(f[hson[x]][0] + g[x][0], f[hson[x]][1] + g[x][0]);
f[x][1] = f[hson[x]][0] + g[x][1];
}
il void upd(int pos, int val) { // 把真实编号为 pos 的节点权值修改为 val
Matrix tmp, tmp2;
using SegmentTree::segtPtr;
using SegmentTree::T;
T[segtPtr[pos]].val[{1, 0}] += val - a[pos], a[pos] = val;
while (true) {
// 修改线段树
tmp = SegmentTree::qry(1, id[top[pos]], ed[top[pos]]);
SegmentTree::upd(segtPtr[pos]);
tmp2 = SegmentTree::qry(1, id[top[pos]], ed[top[pos]]);
pos = fa[top[pos]];
if (!pos)
return;
// 修改矩阵
Matrix &cur = T[segtPtr[pos]].val;
cur[{0, 0}] +=
max(tmp2[{0, 0}], tmp2[{1, 0}]) - max(tmp[{0, 0}], tmp[{1, 0}]);
cur[{0, 1}] = cur[{0, 0}];
cur[{1, 0}] += tmp2[{0, 0}] - tmp[{0, 0}];
cur[{1, 1}] = -1e9;
}
}
il int qry() { // 询问
Matrix ans = SegmentTree::qry(1, id[1], ed[1]);
return max(ans[{0, 0}], ans[{1, 0}]);
}
signed main() {
read(n, Q);
For(i, 1, n) read(a[i]);
For(i, 1, n - 1) {
int u, v;
read(u, v);
T[u].pb(v), T[v].pb(u);
}
dfs1(1, 0);
top[1] = 1, dfs2(1, 1);
SegmentTree::build(1, 1, n);
while (Q--) {
int x, y;
read(x, y);
upd(x, y);
printf("%d\n", qry());
}
return 0;
}