分析:
动态DP板子题,
DP定义式为
f
(
i
,
0
)
,
f
(
i
,
1
)
f(i,0),f(i,1)
f(i,0),f(i,1)分别表示第i为根的子树中的最大值,以i为根的子树的最大答案,以及第i为根的子树中,与i相连的最大联通子树。
转移:
f
(
x
,
1
)
=
max
{
∑
f
(
u
,
1
)
+
v
a
l
x
,
0
}
f(x,1)=\max\{\sum f(u,1)+val_x,0\}
f(x,1)=max{∑f(u,1)+valx,0}
f
(
x
,
0
)
=
max
{
max
{
f
(
u
,
0
)
}
,
f
(
x
,
1
)
}
f(x,0)=\max\{\max\{f(u,0)\},f(x,1)\}
f(x,0)=max{max{f(u,0)},f(x,1)}
其中u为x的子节点。
然后,套路地分出轻儿子
l
f
(
x
,
1
)
=
max
{
∑
f
(
l
u
,
1
)
+
v
a
l
x
,
0
}
lf(x,1)=\max\{\sum f(lu,1)+val_x,0\}
lf(x,1)=max{∑f(lu,1)+valx,0}
l
f
(
x
,
0
)
=
max
{
{
f
(
l
u
,
0
)
}
,
l
f
(
x
,
1
)
}
lf(x,0)=\max\{\{f(lu,0)\},lf(x,1)\}
lf(x,0)=max{{f(lu,0)},lf(x,1)}
第二个取max的显然需要set来维护了
然后是重链
f
(
i
,
1
)
=
∑
f
(
i
−
1
,
1
)
+
l
f
(
i
,
1
)
f(i,1)=\sum f(i-1,1)+lf(i,1)
f(i,1)=∑f(i−1,1)+lf(i,1)
f
(
i
,
0
)
=
max
{
f
(
i
−
1
,
0
)
,
l
f
(
i
,
0
)
}
f(i,0)=\max\{ f(i-1,0),lf(i,0)\}
f(i,0)=max{f(i−1,0),lf(i,0)}
很容易得到转移矩阵:
[
0
,
f
(
i
,
0
)
,
f
(
i
,
1
)
]
∗
[
0
l
f
(
i
,
0
)
0
−
∞
0
−
∞
−
∞
l
f
(
i
,
1
)
l
f
(
i
,
1
)
]
[0,f(i,0),f(i,1)]*\begin{bmatrix} 0 &lf(i,0) & 0\\ -∞ & 0 & -∞ \\ -∞ & lf(i,1) & lf(i,1)\end{bmatrix}
[0,f(i,0),f(i,1)]∗⎣⎡0−∞−∞lf(i,0)0lf(i,1)0−∞lf(i,1)⎦⎤
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 200010
#define INF 10000000000000000ll
using namespace std;
typedef long long ll;
struct Matrix{
ll a[3][3];
Matrix operator *(const Matrix &b) const {
Matrix tmp;
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
tmp.a[i][j]=-INF;
for(int k=0;k<3;k++)
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
tmp.a[i][j]=max(tmp.a[i][j],a[i][k]+b.a[k][j]);
return tmp;
}
ll* operator [](const int &x){
return a[x];
}
}mul[MAXN],w[MAXN];
multiset<ll> maxp[MAXN];
ll val[MAXN];
int siz[MAXN],son[MAXN],lsiz[MAXN];
int s[MAXN][2];
struct node{
int u;
node *nxt;
}edge[MAXN*2];
node *head[MAXN],*ncnt=edge;
void add_edge(int u,int v){
ncnt++;
ncnt->u=v;
ncnt->nxt=head[u];
head[u]=ncnt;
ncnt++;
ncnt->u=u;
ncnt->nxt=head[v];
head[v]=ncnt;
}
void dfs(int x){
siz[x]=1;
for(node *e=head[x];e;e=e->nxt){
int u=e->u;
if(siz[u])
continue;
dfs(u);
siz[x]+=siz[u];
if(siz[u]>siz[son[x]])
son[x]=u;
}
}
void update(int x){
if(s[x][0]||son[x]==0)
mul[x]=mul[s[x][0]]*w[x];
else
mul[x]=w[x];
if(s[x][1])
mul[x]=mul[x]*mul[s[x][1]];
}
int fa[MAXN];
void setchild(int u,int v){
w[u][2][1]+=mul[v][0][2];
w[u][2][2]=w[u][2][1];
maxp[u].insert(mul[v][0][1]);
w[u][0][1]=*maxp[u].rbegin();
w[u][0][1]=max(w[u][0][1],w[u][2][1]);
fa[v]=u;
}
bool used[MAXN];
int st[MAXN],tp;
int build(int l,int r){
if(l>r)
return 0;
int tots=0,pres=0;
for(int i=l;i<=r;i++)
tots+=lsiz[i];
for(int i=l;i<=r;i++){
pres+=lsiz[i];
if(pres*2>=tots){
int x=st[i];
s[x][0]=build(l,i-1);
s[x][1]=build(i+1,r);
if(s[x][0])
fa[s[x][0]]=x;
if(s[x][1])
fa[s[x][1]]=x;
update(x);
return x;
}
}
}
int build_tree(int x){
for(int i=x;i;i=son[i]){
used[i]=1;
lsiz[i]=siz[i]-siz[son[i]];
}
for(int i=x;i;i=son[i])
for(node *e=head[i];e;e=e->nxt){
int u=e->u;
if(used[u])
continue;
int rs=build_tree(u);
setchild(i,rs);
}
tp=0;
for(int i=x;i;i=son[i])
st[++tp]=i;
reverse(st+1,st+1+tp);
return build(1,tp);
}
void change(int x,ll Val){
w[x][2][1]+=Val-val[x];
w[x][2][2]=w[x][2][1];
if(maxp[x].size())
w[x][0][1]=*maxp[x].rbegin();
else
w[x][0][1]=0;
w[x][0][1]=max(w[x][0][1],w[x][2][1]);
val[x]=Val;
int u,v;
for(int i=x;i;i=fa[i]){
if(fa[i]&&s[fa[i]][0]!=i&&s[fa[i]][1]!=i){
v=i;
u=fa[i];
maxp[u].erase(maxp[u].find(mul[v][0][1]));
w[u][2][1]-=mul[v][0][2];
update(i);
maxp[u].insert(mul[v][0][1]);
w[u][0][1]=*maxp[u].rbegin();
w[u][2][1]+=mul[v][0][2];
w[u][2][2]=w[u][2][1];
w[u][0][1]=max(w[u][0][1],w[u][2][1]);
}
else
update(i);
}
}
ll Query(int x){
Matrix tmp;
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
tmp[i][j]=0;
if(son[x]==0)
return max(0ll,val[x]);
if(s[x][0])
tmp=mul[s[x][0]]*w[x];
else
tmp=w[x];
for(int i=x;fa[i]&&(s[fa[i]][0]==i||s[fa[i]][1]==i);i=fa[i]){
int u=fa[i];
if(s[u][1]==i){
if(s[u][0]||son[u]==0)
tmp=mul[s[u][0]]*w[u]*tmp;
else
tmp=w[u]*tmp;
}
}
return tmp[0][1];
}
int n,m,u,v;
char opt[4];
int main(){
SF("%d%d",&n,&m);
for(int i=1;i<=n;i++){
SF("%lld",&val[i]);
w[i][2][1]=w[i][2][2]=w[i][0][1]=val[i];
w[i][1][0]=w[i][1][2]=w[i][2][0]=-INF;
}
for(int i=1;i<n;i++){
SF("%d%d",&u,&v);
add_edge(u,v);
}
dfs(1);
int rt=build_tree(1);
for(int i=1;i<=m;i++){
SF("%s",opt);
if(opt[0]=='Q'){
SF("%d",&u);
PF("%lld\n",Query(u));
}
else{
SF("%d%d",&u,&v);
change(u,v);
}
}
}