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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

[总结] 动态DP学习笔记

發布時間:2025/3/21 编程问答 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [总结] 动态DP学习笔记 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

學習了一下動態DP

問題的來源:
給定一棵 \(n\) 個節點的樹,點有點權,有 \(m\) 次修改單點點權的操作,回答每次操作之后的最大帶權獨立集大小。

首先一個顯然的 \(O(nm)\) 的做法就是每次做一遍樹形DP(這也是我在noip考場上唯一拿到的部分分),直接考慮如何優化這個東西。

簡化一下問題,假如這棵樹是一條鏈,那就變得很簡單了,可以直接拿線段樹維護矩陣加速。

可是如果每個點不止有一個兒子呢?
我們首先樹剖一下。
\(g[i][0]=\sum\limits_{j\in lightson} \max(f[j][0],f[j][1])\)
\(g[i][1]=a[i]+\sum\limits_{j\in lightson} f[j][0]\)
\(g[i][0]\) 表示 \(i\) 的所有輕兒子的 \(\max(f[j][0],f[j][1])\) 之和,\(g[i][1]\) 表示 \(i\) 的所有輕兒子的 \(g[j][0]\) 之和與 \(a[i]\) 的和。

那轉移方程就可以改寫為 \(f[i][0]=\max(g[i][0]+f[son[i]][0],g[i][0]+f[son[i]][1])\)
\(f[i][1]=g[i][1]+f[son[i]][0]\)

這就可以放在線段樹上維護矩陣了。
即每個點維護一個 \(\quad\begin{matrix}g[i][0]&g[i][0]\\-\infty&g[i][1]\end{matrix}\)。然后在線段樹上維護連乘積就好。

還有一點就是修改的時候,要一直跳 \(top\),可以這樣理解:假設當前更改了點 \(x\) 的點權,那么就會改變 \(f[top[x]]\) 的值,緊接著就會影響 \(g[fa[top[x]]]\) 的值,所以我們要一直向上跳 \(top\) 修改才能維護好。

最后放一下代碼:

#pragma GCC optimize(2) #include<bits/stdc++.h> using std::min; using std::max; using std::swap; using std::vector; typedef double db; typedef long long ll; #define pb(A) push_back(A) #define pii std::pair<int,int> #define all(A) A.begin(),A.end() #define mp(A,B) std::make_pair(A,B) const int N=1e5+5; const int inf=1e9; #define ls x<<1 #define rs x<<1|1 #define lss ls,l,mid,ql,qr #define rss rs,mid+1,r,ql,qrint tot,dfn[N],top[N],end[N]; int n,m,v[N],sze[N],son[N],f[N][2]; int cnt,head[N],g[N][2],fa[N],fs[N];struct Edge{int to,nxt; }edge[N<<1];void add(int x,int y){edge[++cnt].to=y;edge[cnt].nxt=head[x];head[x]=cnt; }struct Mat{int a[3][3];Mat(){memset(a,0xcf,sizeof a);}friend Mat operator*(Mat x,Mat y){Mat z;for(int i=1;i<=2;i++)for(int k=1;k<=2;k++)for(int j=1;j<=2;j++)z.a[i][j]=max(x.a[i][k]+y.a[k][j],z.a[i][j]);return z;} }sum[N<<2],val[N];int getint(){int X=0,w=0;char ch=getchar();while(!isdigit(ch))w|=ch=='-',ch=getchar();while( isdigit(ch))X=X*10+ch-48,ch=getchar();if(w) return -X;return X; }void dfs(int now){sze[now]=1;for(int i=head[now];i;i=edge[i].nxt){int to=edge[i].to;if(sze[to]) continue;fa[to]=now;dfs(to);sze[now]=sze[to];son[now]=sze[son[now]]>sze[to]?son[now]:to;} }void dfs(int now,int low){dfn[now]=++tot;top[now]=low;fs[tot]=now;if(son[now]) dfs(son[now],low);for(int i=head[now];i;i=edge[i].nxt){int to=edge[i].to;if(dfn[to]) continue;dfs(to,to);g[now][0]+=max(f[to][0],f[to][1]);g[now][1]+=f[to][0];} if(son[now]) end[now]=end[son[now]];else end[now]=now;g[now][1]+=v[now];f[now][0]=g[now][0]+max(f[son[now]][0],f[son[now]][1]);f[now][1]=g[now][1]+f[son[now]][0]; }void pushup(int x){sum[x]=sum[ls]*sum[rs]; }void build(int x,int l,int r){if(l==r) return sum[x]=val[fs[l]],void();int mid=l+r>>1; build(ls,l,mid),build(rs,mid+1,r);pushup(x); }void init(){for(int i=1;i<=n;i++)val[i].a[1][1]=val[i].a[1][2]=g[i][0],val[i].a[2][1]=g[i][1],val[i].a[2][2]=-inf;build(1,1,n); }Mat query(int x,int l,int r,int ql,int qr){if(ql<=l and r<=qr) return sum[x];int mid=l+r>>1;if(qr<=mid) return query(lss);if(ql>mid) return query(rss);return query(lss)*query(rss); }Mat ask(int x){return query(1,1,n,dfn[top[x]],dfn[end[x]]); }void modify(int x,int l,int r,int ql,int qr){if(l==r) return sum[x]=val[fs[l]],void();int mid=l+r>>1;ql<=mid?modify(lss):modify(rss);pushup(x); }void change(int x,int y){val[x].a[2][1]+=y-v[x]; v[x]=y;Mat pre,nxt;while(x){pre=ask(x);modify(1,1,n,dfn[x],dfn[x]);nxt=ask(x);x=fa[top[x]];val[x].a[1][1]+=max(nxt.a[1][1],nxt.a[2][1])-max(pre.a[1][1],pre.a[2][1]);val[x].a[1][2]=val[x].a[1][1];val[x].a[2][1]+=nxt.a[1][1]-pre.a[1][1];} }signed main(){n=getint(),m=getint();for(int i=1;i<=n;i++) v[i]=getint();for(int i=1;i<n;i++){int x=getint(),y=getint();add(x,y),add(y,x);} dfs(1),dfs(1,1),init();while(m--){int x=getint(),y=getint();change(x,y);Mat ans=ask(1);printf("%d\n",max(ans.a[1][1],ans.a[2][1]));} return 0; }

然后兩道例題:

BZOJ4712 洪水

題意

給出一棵樹,點有點權。多次增加某個點的點權,并在某一棵子樹中詢問:選出若干個節點,使得每個葉子節點到根節點的路徑上至少有一個節點被選擇,求選出的點的點權和的最小值。

Sol

還是動態DP。

先把DP式子列出來: \(f[i]=\min(a[i],\sum\limits_{j\in son[i]} f[j])\),然后套路設 \(g[i]=\sum\limits_{j\in lightson[i]} f[j]\),于是 \(f[i]=\min(a[i],g[i]+f[son[i]])\)。

又可以寫成矩陣相乘的形式:
\[ \begin{matrix}f[son[i]]\\0\end{matrix}\times \begin{matrix}g[i]&a[i]\\\infty&0\end{matrix}=\begin{matrix}f[i]\\0\end{matrix} \]
然后動態DP就行了。

需要注意一點的是在 \(change\) 函數里,\(pre,nxt\) 的矩陣應該是 \(ask(top[x])\) 而不是 \(ask(x)\)。

NOIP2018 保衛王國

題意

給出一棵樹,點有點權。每次強制選或不選兩個節點,求最小權覆蓋集。

Sol

首先有個定理:最小權覆蓋集=全集-最大權獨立集。然后就是luogu模板題了。

轉載于:https://www.cnblogs.com/YoungNeal/p/10360291.html

總結

以上是生活随笔為你收集整理的[总结] 动态DP学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。

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

主站蜘蛛池模板: 中文字幕综合在线 | 国产51自产区 | 春色网站 | 男女无套免费视频网站动漫 | 一二三区不卡 | 亚洲AV成人无码精电影在线 | 日韩中文字幕第一页 | 国产又粗又猛又爽免费视频 | 欧美专区亚洲专区 | 欧洲金发美女大战黑人 | 国产91啪 | 欧美激情一区 | 亚洲系列在线观看 | 亚洲大片精品 | 日韩国产精品一区二区三区 | 婷婷成人av| 欧美日韩精品一区二区在线观看 | 自拍偷拍第一页 | 欧美视频综合 | 亚洲精华国产精华精华液网站 | 欧美激情va永久在线播放 | 日韩欧美一区二区在线 | 亚洲国产一级 | 蜜桃av成人永久免费 | 99xav| 天堂网视频 | 欧美射射 | av亚洲在线观看 | 大陆极品少妇内射aaaaaa | 99久久精品免费视频 | 丰满人妻一区二区三区免费 | 免费在线观看av网站 | 毛片最新网址 | 你懂的欧美| 在线观看欧美精品 | 久久精品一区二区三区不卡牛牛 | 日日碰碰 | 麻豆视频软件 | 欧美乱码精品一区二区 | 熟女高潮一区二区三区视频 | 精品动漫一区二区三区 | 中文字幕国产专区 | 三级无遮挡 | 欧美精品在线一区二区三区 | 免费黄色av网址 | 中文字幕你懂的 | 亚洲自拍偷拍图 | 亚洲经典视频 | 精品国产一区二区三区在线观看 | 第四色男人天堂 | 色婷婷综合久久久久中文字幕 | 免费一区二区三区视频在线 | 日韩另类av | 国产精品久久久久久久久久小说 | 亚洲九九在线 | 亚洲综合黄色 | 日色视频| 少妇被中出| 超碰男人的天堂 | 国产色频 | 激情福利视频 | 夜夜涩| 国产一区二区精华 | 亚洲欧洲日产av | 精品黄色片 | 97xxxxx| 苍井空亚洲精品aa片在线播放 | 久久国产精品免费看 | 欧美挤奶吃奶水xxxxx | 在线观看欧美国产 | 日韩精品――色哟哟 | 久久桃色 | 九九在线精品视频 | 天天热天天干 | 国产天堂资源 | 亚洲一区二区三区不卡视频 | 在线观看自拍 | 日韩精品成人无码专区免费 | 亚洲国产精品无码专区 | www.伊人| 久久人人做 | 黄色片aa | 性一交一乱一色一视频麻豆 | 超碰在线免费看 | 久久精品视频网 | 欧美揉bbbbb揉bbbbb| 国产在线精品一区 | 国产精品久久久久久妇女6080 | 亚洲国产综合在线 | 五月天国产在线 | 午夜爽爽爽 | 一区www | 欧美综合图片 | 春闺艳妇(h)高h产乳 | 18深夜在线观看免费视频 | www夜插内射视频网站 | 伊人久久婷婷 | 中国人妖和人妖做爰 | 亚洲视频二区 |