luoguP4719 【模板】“动态 DP“&动态树分治

很容易写出转移方程以及状态的定义
F [ i ] [ 0 / 1 ] : F[i][0/1]: F[i][0/1]:以i节点为根的子树,选/不选i节点的最大权独立集
F [ i ] [ 0 ] = s i g a m ( m a x ( f [ s o n ] [ 0 ] , f [ s o n ] [ 1 ] ) ) F[i][0] = sigam(max(f[son][0] , f[son][1])) F[i][0]=sigam(max(f[son][0],f[son][1]))
F [ i ] [ 1 ] = v a l [ i ] + s i g a m ( f [ s o n ] [ 0 ] ) F[i][1] = val[i] + sigam(f[son][0] ) F[i][1]=val[i]+sigam(f[son][0])

然后发现,如果要修改的话,只按照上面的状态定义来做是不行的
于是可以尝试对原树进行树po
并且由此可以得到新的转移

g [ i ] [ 0 ] = s i g a m ( m a x ( f [ s o n ] [ 0 ] , f [ s o n ] [ 1 ] ) ) ( 并 且 s o n 不 是 i 节 点 的 重 儿 子 ) g[i][0] = sigam(max(f[son][0] , f[son][1]))(并且son不是i节点的重儿子) g[i][0]=sigam(max(f[son][0],f[son][1]))(soni)
g [ i ] [ 1 ] = s i g a m ( f [ s o n ] [ 0 ] ) ( 并 且 s o n 不 是 i 节 点 的 重 儿 子 ) g[i][1] = sigam(f[son][0])(并且son不是i节点的重儿子) g[i][1]=sigam(f[son][0])(soni)
F [ i ] [ 0 / 1 ] : F[i][0/1]: F[i][0/1]:以i节点为根的子树,选/不选i节点的最大权独立集


F [ i ] [ 0 ] = g [ i ] [ 0 ] + m a x ( f [ c h [ n o w ] [ 0 ] ] , f [ c h [ n o w ] [ 1 ] ] ) F[i][0] = g[i][0] + max(f[ch[now][0]] , f[ch[now][1]]) F[i][0]=g[i][0]+max(f[ch[now][0]],f[ch[now][1]])
F [ i ] [ 1 ] = v a l [ i ] + g [ i ] [ 1 ] + f [ c h [ n o w ] ] [ 0 ] F[i][1] = val[i] + g[i][1] + f[ch[now]][0] F[i][1]=val[i]+g[i][1]+f[ch[now]][0]

然后将上面式子 写成矩阵乘法形式(方便书写)
[ g [ i ] [ 0 ] g [ i ] [ 0 ] g [ i ] [ 1 ] + v a l [ i ] − i n f ] ∗ [ f [ c h [ n o w ] ] [ 0 ] f [ c h [ n o w ] ] [ 1 ] ] = \left[ \begin{matrix} g[i][0] & g[i][0] \\ g[i][1] + val[i] & -inf \end{matrix} \right] * \left[ \begin{matrix} f[ch[now]][0] \\ f[ch[now]][1] \end{matrix} \right]= [g[i][0]g[i][1]+val[i]g[i][0]inf][f[ch[now]][0]f[ch[now]][1]]=
[ f [ i ] [ 0 ] f [ i ] [ 1 ] ] \left[ \begin{matrix} f[i][0] \\ f[i][1] \end{matrix} \right] [f[i][0]f[i][1]]


然后发现可以将上面的那个方程一直递归下去。。。。(恰好是链底到链顶)

然后就可以优美的解决查询问题

考虑修改
考虑修改对应节点的g矩阵时,会对当前节点所处链顶节点的父亲的g矩阵影响
再修改,在往上。。直至修改到1为止

综上
这个 紫题就被这么愉快的解决了

#include<bits/stdc++.h>
#define MAXN 100005
using namespace std;

int n,m,a[MAXN],tot,h[MAXN];
int sz[MAXN],ch[MAXN],dep[MAXN],f[MAXN],yxx[MAXN][2],g[MAXN][2];
int dex,dfn[MAXN],id[MAXN],tp[MAXN],maxl[4];
int last[MAXN];

struct node{
	int from,to,next;
}e[MAXN << 1];

struct Ma{
	int a[2][2];
	void init(){
		a[0][0] = a[0][1] = a[1][0] = a[1][1] = 0;
		return;
	}
}t[MAXN * 8];

Ma operator * (Ma x , Ma y){
	Ma z;
	z.a[0][0] = max(x.a[0][0] + y.a[0][0] , x.a[0][1] + y.a[1][0]);
	z.a[0][1] = max(x.a[0][0] + y.a[0][1] , x.a[0][1] + y.a[1][1]);
	z.a[1][0] = max(x.a[1][0] + y.a[0][0] , x.a[1][1] + y.a[1][0]);
	z.a[1][1] = max(x.a[1][0] + y.a[0][1] , x.a[1][1] + y.a[1][1]);
	return z;
}

void add(int x , int y){
	tot++;
	e[tot].from = x;
	e[tot].to = y;
	e[tot].next = h[x];
	h[x] = tot;
}

void dfs(int now , int fa){
	yxx[now][1] = a[now] , yxx[now][0] = 0;
	f[now] = fa , dep[now] = dep[fa] + 1 , sz[now] = 1;
	for(int i = h[now] ; i != (-1) ; i = e[i].next){
		if(e[i].to == fa)continue;
		dfs(e[i].to , now);sz[now] = sz[now] + sz[e[i].to];
		if(sz[ch[now]] < sz[e[i].to])ch[now] = e[i].to;
		yxx[now][0] = yxx[now][0] + max(yxx[e[i].to][0] , yxx[e[i].to][1]);
		yxx[now][1] = yxx[now][1] + yxx[e[i].to][0];
	}
}

void dfs2(int now , int fa){
	dfn[now] = ++dex;
	last[tp[now]] = dex;
	id[dex] = now;
	g[now][1] = a[now];
	if(ch[now]){
		tp[ch[now]] = tp[now];
		dfs2(ch[now] , now);
	}
	for(int i = h[now] ; i != (-1) ; i = e[i].next){
		if(e[i].to == fa || e[i].to == ch[now])continue;
		tp[e[i].to] = e[i].to;
		dfs2(e[i].to , now);
		g[now][0] = g[now][0] + max(yxx[e[i].to][0] , yxx[e[i].to][1]);
		g[now][1] = g[now][1] + yxx[e[i].to][0];
	}
}

void build(int rt , int l , int r){
	if(l == r){
		t[rt].a[0][0] = g[id[l]][0];
		t[rt].a[1][0] = g[id[l]][0];
		t[rt].a[1][1] = -99999999;
		t[rt].a[0][1] = g[id[l]][1];
		return;
	}
	int mid = (l + r) >> 1;
	build(rt << 1 , l , mid);
	build((rt << 1) | 1 , mid + 1 , r);
	t[rt] = t[rt << 1] * t[(rt << 1) | 1];
	return;
}

void update(int rt , int l , int r , int x){
	if(r < x || l > x)return;
	if(l == r){
		t[rt].a[0][0] = g[id[l]][0];
		t[rt].a[1][0] = g[id[l]][0];
		t[rt].a[1][1] = -99999999;
		t[rt].a[0][1] = g[id[l]][1];
		return;
	}
	int mid = (l + r) >> 1;
	update(rt << 1 , l , mid , x);
	update((rt << 1) | 1 , mid + 1 , r , x);
	t[rt] = t[rt << 1] * t[(rt << 1) | 1];
	return;
}

Ma que(int rt , int l , int r , int x , int y){
	if(x <= l && r <= y)return t[rt];
	int mid = (l + r) >> 1;
	if(mid >= y)return que(rt << 1 , l , mid , x , y);
	if(mid < x)return que((rt << 1) | 1 , mid + 1 , r , x , y);
	return que(rt << 1 , l , mid , x , y) * que((rt << 1) | 1 , mid + 1 , r , x , y);
}

void out(){
	Ma zz = que(1 , 1 , n , dfn[1] , last[1]);
	maxl[0] = max(zz.a[0][0] , zz.a[0][1]);
	maxl[1] = max(zz.a[1][0] , zz.a[1][1]);
	cout<<max(maxl[0] , maxl[1])<<endl;
}

void sp_update(int x , int y){
	int zz;
	Ma zz1 , zz2;
	g[x][1] = g[x][1] - a[x] + y , a[x] = y;
	while(tp[x] != 1){
		zz1 = que(1 , 1 , n , dfn[tp[x]] , last[tp[x]]);
		update(1 , 1 , n , dfn[x]);
		zz2 = que(1 , 1 , n , dfn[tp[x]] , last[tp[x]]);
		x = f[tp[x]];
		zz = max(zz1.a[0][0] , zz1.a[0][1]) - max(zz2.a[0][0] , zz2.a[0][1]);
		g[x][0] = g[x][0] - zz;
		zz = max(zz1.a[1][0] , zz1.a[1][1]) - max(zz2.a[1][0] , zz2.a[1][1]);
		g[x][1] = g[x][1] - zz;
	}
	update(1 , 1 , n , dfn[x]);
	out();
}

void init(){
	memset(h , -1 , sizeof(h));
	tot = dex = 0;tp[1] = 1;
	cin>>n>>m;int x,y;
	for(int i = 1 ; i <= n ; i++)cin>>a[i];
	for(int i = 1 ; i < n ; i++){
		cin>>x>>y;
		add(x , y) , add(y , x);
	}
	dfs(1 , 1);
	dfs2(1 , 1);
	build(1 , 1 , n);
}

void solve(){
	//for(int i = 1 ; i <= n ; i++)cout<<"   "<<i<<"  "<<g[i][0]<<"  "<<g[i][1]<<endl;
	int x,y;
	while(m--){
		cin>>x>>y;
		sp_update(x , y);
	}
}

int main(){
	init();
	solve();
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值