P4719 【模板】動態dp
P4719 【模板】動態dp
神仙東西orz
動態dp簡單來說就是dp可以用矩陣來轉移,用LCT來維護矩陣的轉移。
那麼簡單來說就是pj難度的DP,tg難度的矩乘,以及noip+難度的LCT。
pj難度dp:設\(dp[i][j]\)表示點i不選/選。\(f[x][0]=\sum f[son][1],f[x][1]=\sum \max(f[son][0],f[son][1])\)。
tg難度的矩乘:用新的姿勢來定義矩乘,把*換成+,+換成取max。因為依然具有分配率,所以還是可以矩乘的。
noip+難度LCT:LCT要維護子樹資訊,設\(g[x][0/1]\)表示只看x和的虛子樹的答案。
眾所周知LCT上每個點都有重兒子。
\(f[x][0]=\max(g[x][0]+f[heavyson][0],g[x][0]+f[heavyson][1])\)
\(f[x][1]=g[x][1]+f[heavyson][0]\)
f可以用一個1*2的矩形\(\left[\begin{matrix}f[x][0] && f[x][1]\\\end{matrix}\right]\)來搞。
配一個矩乘的東西。上面這個很好弄,只要
\[ \left[ \begin{matrix} f[heavyson][0] && f[heavyson][1] \end{matrix} \right] \times \left[ \begin{matrix} g[x][0] && ??\\ g[x][0] && ??\\ \end{matrix} \right] =\left[\begin{matrix}f[x][0] && f[x][1]\\\end{matrix}\right] \]
就好了。下面那個不太好搞,不過可以化成
\(f[x][1]=\max(g[x][1]+f[heavyson][0],-inf)\)
所以乘的矩陣應該是
\[ \left[ \begin{matrix} f[heavyson][0] && f[heavyson][1] \end{matrix} \right] \times \left[ \begin{matrix} g[x][0] && g[x][1]\\ g[x][0] && -inf\\ \end{matrix} \right] =\left[\begin{matrix}f[x][0] && f[x][1]\\\end{matrix}\right] \]
這樣就好了。
感覺還有很多東西沒講清,反正我部落格也沒人看,咕咕咕著吧。順便推薦一篇
https://www.luogu.org/blog/gkxx-is-here/solution-p4751
(程式碼是P4751 【動態dp【加強版】】的)
#include<bits/stdc++.h>
#define il inline
#define vd void
#define inf 100000000
il int gi(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')f=-1;
ch=getchar();
}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return x*f;
}
struct Matrix{
int s[2][2];
Matrix(){s[0][0]=s[0][1]=s[1][0]=s[1][1]=-inf;}
Matrix(int a,int b,int c,int d){s[0][0]=a,s[0][1]=b,s[1][0]=c,s[1][1]=d;}
};
il Matrix operator*(const Matrix&a,const Matrix&b){return Matrix(std::max(a.s[0][0]+b.s[0][0],a.s[0][1]+b.s[1][0]),std::max(a.s[0][0]+b.s[0][1],a.s[0][1]+b.s[1][1]),std::max(a.s[1][0]+b.s[0][0],a.s[1][1]+b.s[1][0]),std::max(a.s[1][0]+b.s[0][1],a.s[1][1]+b.s[1][1]));}
#define maxn 1000010
int V[maxn];
int ch[maxn][2],fa[maxn];
int fir[maxn],dis[maxn<<1],nxt[maxn<<1],id;
il vd link(int a,int b){nxt[++id]=fir[a],fir[a]=id,dis[id]=b;}
int dp[maxn][2];
Matrix f[maxn],g[maxn];
il vd dfs(int x){
dp[x][1]=V[x];
for(int i=fir[x];i;i=nxt[i]){
if(fa[x]==dis[i])continue;
fa[dis[i]]=x;
dfs(dis[i]);
dp[x][0]+=std::max(dp[dis[i]][0],dp[dis[i]][1]);
dp[x][1]+=dp[dis[i]][0];
}
g[x].s[0][0]=g[x].s[0][1]=dp[x][0];
g[x].s[1][0]=dp[x][1];
}
il bool isrt(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
il vd upd(int x){
f[x]=g[x];
if(ch[x][0])f[x]=f[ch[x][0]]*f[x];
if(ch[x][1])f[x]=f[x]*f[ch[x][1]];
}
il vd rotate(int x){
int y=fa[x],z=fa[y],o=x==ch[y][1];
if(!isrt(y))ch[z][y==ch[z][1]]=x;fa[x]=z;
ch[y][o]=ch[x][!o],fa[ch[x][!o]]=y;
ch[x][!o]=y,fa[y]=x;upd(y);
}
il vd splay(int x){
int y,z;
while(!isrt(x)){
y=fa[x],z=fa[y];
if(!isrt(y))rotate(((x==ch[y][1])==(y==ch[z][1]))?y:x);
rotate(x);
}
upd(x);
}
il vd access(int x){
for(int y=0;x;x=fa[y=x]){
splay(x);
if(ch[x][1])g[x].s[0][0]+=std::max(f[ch[x][1]].s[0][0],f[ch[x][1]].s[1][0]),g[x].s[1][0]+=f[ch[x][1]].s[0][0];
if(y)g[x].s[0][0]-=std::max(f[y].s[0][0],f[y].s[1][0]),g[x].s[1][0]-=f[y].s[0][0];
g[x].s[0][1]=g[x].s[0][0];ch[x][1]=y;
upd(x);
}
}
int main(){
int n=gi(),m=gi(),a,b;
for(int i=1;i<=n;++i)V[i]=gi();
for(int i=1;i<n;++i)a=gi(),b=gi(),link(a,b),link(b,a);
dfs(1);
int lst=0;
while(m--){
a=gi()^lst,b=gi();
access(a),splay(a);
g[a].s[1][0]+=b-V[a];upd(a);V[a]=b;
splay(1),printf("%d\n",lst=std::max(f[1].s[0][0],f[1].s[1][0]));
}
return 0;
}