我理解的動態dp:
發現dp可以寫成矩陣的形式,因此用資料結構維護矩陣乘積。
對於這道題,顯然有dp:
\(f_\)表示\(x\)的子樹中,x選/不選的最大點獨立集。
\(f_=\sum\limits_\max(f_,f_),f_=\sum\limits_f_+a_x\)
既然在樹上,就用樹剖或者lct解決,本質都是將樹拆成鏈,這裡用樹剖。
設\(son_x\)表示\(x\)的重兒子,\(g_\)表示除去\(son_x\)後的\(f_\)的值。
有:\(f_=g_+\max(f_,f_),f_=g_+f_\),注意\(g_\)初值為\(a_x\)。
dp寫成矩陣的形式:
\(\beging_&g_\\g_& 0\end\beginf_\\ f_\end=\beginf_\\ f_\end\)
注意這裡的矩乘長這樣:
mat operator*(mat a,mat b)
之後就正常樹剖修改查詢即可
code:
#includeusing namespace std;
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
const int maxn=1e5+10;
int n,m,cnt,tim;
int head[maxn],a[maxn],size[maxn],pre[maxn],dep[maxn],son[maxn],dfn[maxn],pos[maxn],top[maxn],ed[maxn];
int f[maxn][2];
struct edgee[maxn<<1];
struct mat
int* operator(int i)
}val[maxn],seg[maxn<<2];
mat operator*(mat a,mat b)
inline void add(int u,int v)
void dfs1(int x,int fa)
void change(int p,int l,int r,int k)
int mid=(l+r)>>1;
if(k<=mid)change(ls(p),l,mid,k);
else change(rs(p),mid+1,r,k);
up(p);
}mat query(int p,int l,int r,int ql,int qr)
inline void trchange(int x,int k)
}int main()
dfs1(1,0);dfs2(1,1);
build(1,1,n);
for(int i=1;i<=m;i++)
return 0;
}
洛谷P4719 模板 動態dp
大概就是一條鏈一條鏈的處理 鏈 在這裡指重鏈 對於每一條鏈,對於其上每乙個點,先算出它自身和所有輕兒子的貢獻,當做這一步中這個點的 權值 然後就變成序列上dp,直接用線段樹維護 線段樹版本o n log 2 1 include2 include3 include4 using namespace s...
洛谷P4719 模板 動態 DP
給定一棵 n 個點的樹,點帶點權。有 m 次操作,每次操作給定 x,y 表示修改點 x 的權值為 y 你需要在每次操作之後求出這棵樹的最大權獨立集的權值大小。調到心態 從前天晚上開始就剛這道題。最大權獨立子集即 選出若干個不相鄰的點使得他們的權值最大 摘自akioi的神仙 若沒有修改,這道題就是樹形...
洛谷P4719 動態DP模板
一棵 n 個點的樹,點帶點權。m 次操作,每次操作給定 x,y 表示修改點 x 的權值為 y 每次操作後求出這棵樹的最大權獨立集的權值大小。n,m leq 10 5 首先有乙個 o nm 的 dp 設 f u 0 1 分別表示以 u 為根的子樹中,u 不選 選 的最大獨立集權值大小。f u 0 su...