動態DP(學習筆記)
阿新 • • 發佈:2018-12-02
動態 是貓學長髮明的用來解決樹上帶修DP的問題的演算法。
好像多數是求樹上最大權獨立集?
樹上最大權獨立集我們可以用樹形
地求出來,設
表示
為根的子樹
選或不選的最優方案,可以列出轉移式:
如果帶修改該如何做呢,這個時候就要用樹剖+線段樹+矩陣來解決了。
樹剖+線段樹是常用的解決樹上問題的優秀演算法,想想重鏈一定是一個區間,就可以用線段樹來維護,那麼每個節點只需要維護其他輕兒子,可以把上面的轉移式改一改:
把新的
記為
這樣就實現了維護一棵樹到維護一個序列的轉變
這個轉移怎麼轉化成矩陣的形式?
我們可以改變一下矩陣乘法的運算:
Mat operator *(const Mat &x) const{
Mat ret;
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
for(int k=0;k<2;k++)
ret.g[i][j]=max(ret.g[i][j],g[i][k]+x.g[k][j]);
return ret;
}
然後想想矩陣是什麼:
然後代入矩陣乘法算一算,頓時覺得很有道理啊
於是可以用線段樹維護每個區間的矩陣積,查詢的時候只需要線上段樹上 就好了
然後修改怎麼做呢?可以發現當一個節點的權值改變了,那麼它的鏈頂的節點的 值會改變,再往上,每過一條輕邊,它都會影響那個點的 值,線上段樹上單點修改就好了,因為輕邊是 級別的,線段樹修改也是 級別的,所以修改複雜度是 的,查詢 ,總複雜度
程式碼如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define LL long long
#define N 100005
#define ls cur<<1
#define rs cur<<1|1
#define inf 0x3f3f3f3f
using namespace std;
inline int rd(){
int x=0,f=1;char c=' ';
while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
return x*f;
}
int n,m,a[N],cnt,head[N],f[N][2];
int dfn[N],rk[N],dep[N],fa[N],son[N],siz[N],top[N],ed[N],num;
struct EDGE{
int to,nxt;
}edge[N<<1];
inline void add(int x,int y){
edge[++cnt].to=y; edge[cnt].nxt=head[x]; head[x]=cnt;
}
void dfs1(int u,int fat){
siz[u]=1; int maxson=-1;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to; if(v==fat) continue; fa[v]=u;
dep[v]=dep[u]+1; dfs1(v,u); siz[u]+=siz[v];
if(siz[v]>maxson) maxson=siz[v],son[u]=v;
} return;
}
void dfs2(int u,int t){
top[u]=t; dfn[u]=++num; rk[num]=u; ed[t]=u;
if(!son[u]) return;
dfs2(son[u],t);
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(!dfn[v]) dfs2(v,v);
} return;
}
struct Mat{
int g[2][2];
Mat(){memset(g,0,sizeof g);}
Mat operator *(const Mat &x) const{
Mat ret;
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
for(int k=0;k<2;k++)
ret.g[i][j]=max(ret.g[i][j],g[i][k]+x.g[k][j]);
return ret;
}
}val[N],node[N<<2];
void build(int cur,int L,int R){
if(L==R){
int g0=0,g1=a[rk[L]];
for(int u=rk[L],i=head[u],v;i;i=edge[i].nxt)
if((v=edge[i].to)!=fa[u] && v!=son[u])
g0+=max(f[v][0],f[v][1]),g1+=f[v][0];
node[cur]