洛谷P4719 【模板】动态dp

48 篇文章 0 订阅
23 篇文章 0 订阅

题目链接

 

题解:神奇的动态dp,orz

 

模板:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=100001;
int a[N],e[N*2],head[N],next[N*2],cnt,tot,n,q[N],fa[N],sz[N],son[N],top[N],ed[N],pos[N],idx[N];
ll f[N][2];
struct matrix{
	ll g[2][2];
	matrix(){memset(g,0,sizeof(g));}
	matrix operator *(const matrix &b)const{
 	 matrix c;
 	 int i,j,k;
 	 for(i=0;i<2;i++)
 	  for(j=0;j<2;j++)
 	   for(k=0;k<2;k++)c.g[i][j]=max(c.g[i][j],g[i][k]+b.g[k][j]);
 	 return c;  
  }
}val[N],d[N*4];
void build(int t,int k){
	tot++;
	e[tot]=k;
	next[tot]=head[t];head[t]=tot;
}
void init(){
	q[1]=1;
	int u,i,j,l=0,r=1;
	while(l<r){
		u=q[++l];
		for(i=head[u];i;i=next[i])
		 if(e[i]!=fa[u]){
		 	fa[e[i]]=u;q[++r]=e[i];
		 }
	}
	for(i=n;i;i--){
		sz[q[i]]++;
		sz[fa[q[i]]]+=sz[q[i]];
		if(sz[q[i]]>sz[son[fa[q[i]]]])son[fa[q[i]]]=q[i];
	}
	for(i=1;i<=n;i++)
	 if(!top[q[i]]){
	 	for(j=q[i];j;j=son[j])top[j]=q[i],idx[pos[j]=++cnt]=j;
	 	ed[q[i]]=cnt;
	 }
	for(i=n;i;i--){
		u=q[i];
		f[u][1]=max(0,a[u]);
		for(j=head[u];j;j=next[j])
		 if(e[j]!=fa[u]){
		 	f[u][0]+=max(f[e[j]][0],f[e[j]][1]);
		 	f[u][1]+=f[e[j]][0];
		 }
	} 
}
void bt(int x,int l,int r){
	int u,i;
	if(l==r){
		ll g0=0,g1=a[idx[l]];
		u=idx[l];
		for(i=head[u];i;i=next[i])
		 if(e[i]!=fa[u]&&e[i]!=son[u])g0+=max(f[e[i]][0],f[e[i]][1]),g1+=f[e[i]][0];
		d[x].g[0][0]=d[x].g[0][1]=g0;
		d[x].g[1][0]=g1;
		val[l]=d[x];
		return;
	}
	int mid=(l+r)/2;
	bt(x*2,l,mid);bt(x*2+1,mid+1,r);
	d[x]=d[x*2]*d[x*2+1];
}
matrix query(int x,int l,int r,int t,int k){
	if(l==t&&r==k)return d[x];
	int mid=(l+r)/2;
	if(mid>=k)return query(x*2,l,mid,t,k);
	 else if(t>mid)return query(x*2+1,mid+1,r,t,k);
	  else return query(x*2,l,mid,t,mid)*query(x*2+1,mid+1,r,mid+1,k);
}
matrix ask(int u){
	return query(1,1,n,pos[top[u]],ed[top[u]]);
}
void change(int x,int l,int r,int t){
	if(l==r){
		d[x]=val[l];return;
	}
	int mid=(l+r)/2;
	if(mid>=t)change(x*2,l,mid,t);
	 else change(x*2+1,mid+1,r,t);
	d[x]=d[x*2]*d[x*2+1]; 
}
void change(int u,int x){
	val[pos[u]].g[1][0]+=x-a[u];a[u]=x;
	matrix od,nw;
	//puts("-1");
	while(u){
		//printf("%d %d %d\n",top[u],pos[top[u]],ed[top[u]]);
		od=ask(top[u]);
		//puts("-1");
		change(1,1,n,pos[u]);
		nw=ask(top[u]);
		u=fa[top[u]];
		val[pos[u]].g[0][0]+=max(nw.g[0][0],nw.g[1][0])-max(od.g[0][0],od.g[1][0]);
		val[pos[u]].g[0][1]=val[pos[u]].g[0][0];
		val[pos[u]].g[1][0]+=nw.g[0][0]-od.g[0][0];
	}
}
int main(){
	int t1,i,t,k,u,x;
	matrix T;
	scanf("%d%d",&n,&t1);
	for(i=1;i<=n;i++)scanf("%d",&a[i]);
	for(i=1;i<n;i++){
		scanf("%d%d",&t,&k);
		build(t,k);build(k,t);
	}
	init();
	bt(1,1,n);
	while(t1--){
		scanf("%d%d",&u,&x);
		change(u,x);
	//	puts("-1");
		T=ask(1);
		printf("%lld\n",max(T.g[0][0],T.g[1][0]));
	}
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值