动态DP学习笔记
动态DP实际上就是利用树链剖分的性质快速的维护\(f\)和\(g\),利用矩阵乘法和线段树加速修改过程
\(f\)数组的用途在本质上与LCT动态维护树的重心那个轻儿子子树的用途相同,用来“填”重链维护中留下的坑
水平不行 说不清楚。。。 还是代码最直观。。。
注意矩阵乘法不满足交换律 维护线段树时要注意一下从哪边向哪边合并
还有矩阵乘法最后要return 写函数变量不要重名!!!
/*
注意Matrix的乘法函数
最后要return!!!
否则会出现未知错误。。。
*/
#include<stack>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int U=2,N=1e5+10,M=2e5+10,INF=0x3f3f3f3f;
inline void Read(int &x){
x=0;register char cc='\0';int fff=1;
for(;cc<'0'||cc>'9';cc=getchar())if(cc=='-')fff=-1;
for(;cc>='0'&&cc<='9';cc=getchar())x=(x<<1)+(x<<3)+(cc&15);
x*=fff;
}
int n,m,num,fa[N],val[N],siz[N],dfn[N],real[N];
int tot,bson[N],Top[N],Tail[N],Head[N],Next[M],Adj[M];
struct Matrix{
int len1,len2,t[U][U];
Matrix operator * (const Matrix Other) const{
Matrix c;c.len1=len1;c.len2=Other.len2;
memset(c.t,0xcf,sizeof(c.t));
for(int k=0;k<2;++k)
for(int i=0;i<2;++i)
for(int j=0;j<2;++j)
c.t[i][j]=max((LL)c.t[i][j],(LL)t[i][k]+Other.t[k][j]);
return c;//!!!!!
}
}G[N],Tree[N<<2];
inline void Pushup(int now){Tree[now]=Tree[now<<1]*Tree[now<<1|1];}
void Update(const int ed,const Matrix ad,int now=1,int nowl=1,int nowr=n){
if(nowl==nowr){
Tree[now]=ad;
return;
}
int nowm=(nowl+nowr)>>1;
if(ed<=nowm)Update(ed,ad,now<<1,nowl,nowm);
if(ed>nowm)Update(ed,ad,now<<1|1,nowm+1,nowr);
Pushup(now);
}
Matrix Query(int left,int right,int now=1,int nowl=1,int nowr=n){
if(left<=nowl&&nowr<=right) return Tree[now];
int nowm=(nowl+nowr)>>1;
if(right<=nowm)return Query(left,right,now<<1,nowl,nowm);
if(left>nowm)return Query(left,right,now<<1|1,nowm+1,nowr);
return Query(left,nowm,now<<1,nowl,nowm)
*Query(nowm+1,right,now<<1|1,nowm+1,nowr);
}
void DFS1(int now,int fat){
fa[now]=fat;siz[now]=1;
for(int e=Head[now];e;e=Next[e])
if(Adj[e]!=fat){
DFS1(Adj[e],now);siz[now]+=siz[Adj[e]];
if(siz[Adj[e]]>siz[bson[now]])bson[now]=Adj[e];
}
}
void DFS2(int now,int fat){
fa[now]=fat;
real[dfn[now]=++num]=now;
if(now==bson[fat])Top[now]=Top[fat];
else Top[now]=now;
if(bson[now])DFS2(bson[now],now);
for(int e=Head[now];e;e=Next[e])
if(Adj[e]!=fat&&Adj[e]!=bson[now])
DFS2(Adj[e],now);
Tail[now]=bson[now]?Tail[bson[now]]:now;
}
void Prepare(int now){/*预处理F,G*/
stack<int> S;while(!S.empty())S.pop();
for(int i=now;i;i=bson[/*now*/i])S.push(i);
while(!S.empty()){
int /*now*/u=S.top();S.pop();
int x=0,y=val[/*now*/u];
for(int e=Head[/*now*/u];e;e=Next[e]){
if(Adj[e]!=fa[/*now*/u]&&Adj[e]!=bson[/*now*/u]){
Prepare(Adj[e]);
Matrix q=G[Adj[e]];
x+=max(q.t[0][0],q.t[1][0]);
y+=q.t[0][0];
}
}
Matrix q=(Matrix){2,2,{{x,x},{y,-INF}}};
Update(dfn[/*now*/u],q);
}
G[now]=Query(dfn[now],dfn[Tail[now]]);
/*回溯时计算以自己为Top的重链上的贡献!!!*/
}
void Modify(int now,int vl){
Matrix q=Query(dfn[now],dfn[now]);
q.t[1][0]-=val[now];val[now]=vl;q.t[1][0]+=val[now];
Update(dfn[now],q);
for(int u=Top[now],ft=fa[Top[now]];u;u=Top[ft]){
ft=fa[u];
int x=G[u].t[0][0],y=G[u].t[1][0];
G[u]=Query(dfn[u],dfn[Tail[u]]);
if(ft){
Matrix p=Query(dfn[ft],dfn[ft]);
p.t[0][0]+=max(G[u].t[0][0],G[u].t[1][0])-max(x,y);
p.t[0][1]=p.t[0][0];
p.t[1][0]+=G[u].t[0][0]-x;
Update(dfn[ft],p);
}
}
}
int main()
{
freopen("LG4719.in","r",stdin);
freopen("LG4719.out","w",stdout);
Read(n);Read(m);
for(int i=0;i<(N<<2);++i)Tree[i].len1=Tree[i].len2=2;
for(int i=0;i<N;++i)G[i].len1=G[i].len2=2;
for(int i=1;i<=n;++i)Read(val[i]);
for(int i=1,x,y;i<n;++i){
Read(x);Read(y);
Next[++tot]=Head[x];Head[x]=tot;Adj[tot]=y;
Next[++tot]=Head[y];Head[y]=tot;Adj[tot]=x;
}
DFS1(1,0);DFS2(1,0);
Prepare(1);
while(m--){
int x,y;Read(x);Read(y);
Modify(x,y);Matrix nas=Query(dfn[1],dfn[Tail[1]]);
printf("%d\n",max(nas.t[0][0],nas.t[1][0]));
}
return 0;
}