日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

P4719 【模板】动态dp

發布時間:2025/4/16 编程问答 15 豆豆
生活随笔 收集整理的這篇文章主要介紹了 P4719 【模板】动态dp 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

[題目鏈接] https://www.luogu.org/problemnew/show/P4719

題解(shadowice)

代碼借鑒

求最大獨立集是一個經典的問題,這個轉移如果套上樹剖就可以轉化為序列上的問題,就可以用所謂的矩陣乘法維護了.

\(g[x][0/1]\)代表重兒子以外的答案,\(f[x][0/1]\)代表最終的答案,假如維護好了這兩個信息,那么重鏈上的轉移就是正確的了.

注意矩陣乘法的順序,手模可以發現答案是重鏈上從上到下的g[]相乘再乘上最下面的點的\(f[]\).而最底下的點的\(f[]\)恰好就是\(g[]\),而乘的過程中只要滿足\(g[]\)\(a[0][0]\)\(a[1][0]\)正確就行了,所以最終答案就可以直接是\(rt\)所在的重鏈的矩陣乘起來.

dp用矩陣乘法維護可以參考這道題 .取max操作也可以用矩陣維護.

具體實現:修改某一個點權值就把它的信息更改,直接更新它所在的重鏈的答案,再一路更新上面所有的重鏈.

注意幾點:

\(1.\)證明正確性的時候,一定要把矩陣乘法的順序手模出來,一般要轉化為與樹剖的dfn序相符.

\(2.\)初始的答案在建樹時存進去,所以還要先一遍dfs算出最初的答案.

細節詳見代碼

#include<bits/stdc++.h> using namespace std; typedef long long LL; const LL INF=1e18+7; inline LL read(){register LL x=0,f=1;register char c=getchar();while(c<48||c>57){if(c=='-')f=-1;c=getchar();}while(c>=48&&c<=57)x=(x<<3)+(x<<1)+(c&15),c=getchar();return f*x; }const int MAXN=100005; const int MAXM=200005;struct Edge{int v,next; }e[MAXM]; int first[MAXN],Ecnt=0; inline void Add_edge(int u,int v){e[++Ecnt]=(Edge){v,first[u]};first[u]=Ecnt; }int size[MAXN],top[MAXN],seg[MAXN],rev[MAXN],son[MAXN],fa[MAXN],bot[MAXN],val[MAXN]; LL f[MAXN][2]; int n,m;inline void dfs1(int u,int pre){size[u]=1;for(int i=first[u];i;i=e[i].next){int v=e[i].v;if(v==pre) continue;fa[v]=u;dfs1(v,u);size[u]+=size[v];if(size[v]>size[son[u]]) son[u]=v;} }inline void dfs2(int u,int pre){seg[u]=++seg[0];rev[seg[0]]=u;if(son[u]){top[son[u]]=top[u];dfs2(son[u],u);bot[u]=bot[son[u]];//bot[]的更新}else bot[u]=u;for(int i=first[u];i;i=e[i].next){int v=e[i].v;if(v==pre||v==son[u]) continue; top[v]=v;dfs2(v,u); } }inline void dfs3(int u,int pre){f[u][1]=val[u];for(int i=first[u];i;i=e[i].next){int v=e[i].v;if(v==pre) continue;dfs3(v,u);f[u][1]+=f[v][0];f[u][0]+=max(f[v][0],f[v][1]);//算出初始答案} }struct Matrix{LL a[2][2];//這題矩陣乘法可以直接這么寫inline friend Matrix operator * (Matrix a,Matrix b){Matrix res;res.a[0][0]=max(a.a[0][0]+b.a[0][0],a.a[0][1]+b.a[1][0]);res.a[0][1]=max(a.a[0][0]+b.a[0][1],a.a[0][1]+b.a[1][1]);res.a[1][0]=max(a.a[1][0]+b.a[0][0],a.a[1][1]+b.a[1][0]);res.a[1][1]=max(a.a[1][0]+b.a[0][1],a.a[1][1]+b.a[1][1]);return res;} }g[MAXN<<2],tmp[MAXN];struct SGT{ #define ls (rt<<1) #define rs (rt<<1|1)inline void pushup(int rt){g[rt]=g[ls]*g[rs];}inline void build(int rt,int l,int r){if(l==r){int u=rev[l],g0=0,g1=val[u];for(int i=first[u];i;i=e[i].next){int v=e[i].v;if(v==son[u]||v==fa[u]) continue;g0+=max(f[v][0],f[v][1]);g1+=f[v][0];}tmp[l]=g[rt]=(Matrix){g0,g0,g1,-INF};//建樹時就要算出初始的答案!!!return;}int mid=(l+r)>>1;build(ls,l,mid);build(rs,mid+1,r);pushup(rt);}inline Matrix query(int rt,int l,int r,int x,int y){if(l>=x&&r<=y) return g[rt];int mid=(l+r)>>1;if(y<=mid) return query(ls,l,mid,x,y);if(mid<x) return query(rs,mid+1,r,x,y);return query(ls,l,mid,x,y)*query(rs,mid+1,r,x,y);}inline Matrix GetMat(int u){return query(1,1,n,seg[top[u]],seg[bot[u]]);}inline void modify(int rt,int l,int r,int p){if(l==r&&l==p){g[rt]=tmp[l];return;}int mid=(l+r)>>1;if(p<=mid) modify(ls,l,mid,p);else modify(rs,mid+1,r,p);pushup(rt);}inline void modify(int u,int w){tmp[seg[u]].a[1][0]+=w-val[u],val[u]=w;//細節處理,先更新再說while(u){Matrix a=GetMat(u);modify(1,1,n,seg[u]);//算出u所在的重鏈的答案Matrix b=GetMat(u);u=fa[top[u]];//一路更新上去.if(!u) break;//利用更新前后的差值去更新fa//tmp是一個中間變量,方便更新g[]tmp[seg[u]].a[0][1]=(tmp[seg[u]].a[0][0]+=max(b.a[0][0],b.a[1][0])-max(a.a[0][0],a.a[1][0]));tmp[seg[u]].a[1][0]+=b.a[0][0]-a.a[0][0];}} #undef ls #undef rs }T;int main(){ // freopen("asd.in","r",stdin);n=read(),m=read();for(int i=1;i<=n;i++)val[i]=read();for(int i=1;i<=n-1;i++){int x=read(),y=read();Add_edge(x,y);Add_edge(y,x);//記得建雙向邊}dfs1(1,0);top[1]=1;dfs2(1,0);dfs3(1,0);T.build(1,1,n);for(int i=1;i<=m;i++){int x=read(),y=read();T.modify(x,y);Matrix ans=T.GetMat(1);//答案就轉化為所有的g[]乘起來printf("%lld\n",max(ans.a[0][0],ans.a[1][0]));} }

轉載于:https://www.cnblogs.com/lizehon/p/10428349.html

《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

總結

以上是生活随笔為你收集整理的P4719 【模板】动态dp的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。