动态DP

105 篇文章 0 订阅
47 篇文章 0 订阅

https://www.cnblogs.com/RabbitHu/p/9112811.html
f [ i ] [ 1 ] f[i][1] f[i][1]为选点 i i i的最大权独立集。
f [ i ] [ 0 ] f[i][0] f[i][0]为不选 i i i的最大权独立集。
g [ u ] [ 0 ] g[u][0] g[u][0]为轻儿子都不选的最大值。
g [ u ] [ 1 ] g[u][1] g[u][1]为轻儿子可以选的最大值
[ f [ v ] [ 0 ] , f [ v ] [ 1 ] ] × [ g [ u ] [ 1 ] g [ u ] [ 0 ] + v a l [ u ] g [ u ] [ 1 ] − ∞ ] = [ f [ u ] [ 0 ] , f [ u ] [ 1 ] ] \begin{bmatrix}f[v][0],f[v][1]\end{bmatrix} \times \begin{bmatrix}g[u][1]&g[u][0]+val[u]\\g[u][1]& -\infty\end{bmatrix}=\begin{bmatrix}f[u][0],f[u][1]\end{bmatrix} [f[v][0],f[v][1]]×[g[u][1]g[u][1]g[u][0]+val[u]]=[f[u][0],f[u][1]]
然后乘法换为+,加法换为取max。
LCT日常维护, g g g为虚子树,求链上不满足交换律的积。
AC Code:

#include<bits/stdc++.h>
#define maxn 100005
#define inf 0x3f3f3f3f
using namespace std;

int n,m,val[maxn];
struct mat{
	int a[2][2];
	mat (int d=0){a[0][0]=a[1][1]=d,a[0][1]=a[1][0]=-inf;}
	mat operator *(const mat &B)const{
		mat ret(-inf);
		for(int i=0;i<2;i++)
			for(int j=0;j<2;j++)
				for(int k=0;k<2;k++)
					ret.a[i][k] = max(ret.a[i][k] , a[i][j] + B.a[j][k]);
		return ret;
	}
};
namespace LCT{
	int ch[maxn][2],fa[maxn];
	mat g[maxn],s[maxn];
	#define il inline 
	#define pa fa[x]
	il int inr(int x){ return ch[pa][1]==x; }
	il int isr(int x){ return ch[pa][0]!=x&&ch[pa][1]!=x; }
	il void upd(int x){
		s[x] = s[ch[x][1]] * g[x] * s[ch[x][0]];
	}
	il void rot(int x){
		int y=fa[x],z=fa[y],c=inr(x);
		if(!isr(y)) ch[z][inr(y)]=x;
		(ch[y][c]=ch[x][!c])&&(fa[ch[y][c]]=y);
		fa[fa[ch[x][!c]=y]=x]=z;
		upd(y);
	}
	il void splay(int x){
		for(;!isr(x);rot(x))
			if(!isr(pa)) rot(inr(pa)==inr(x)?pa:x); 
		upd(x);
	}
	il int access(int x,int y=0){
		for(;x;x=fa[y=x]){
			splay(x);
			if(ch[x][1]){
				int a0 = max(s[ch[x][1]].a[0][0],s[ch[x][1]].a[1][0]),
					a1 = max(s[ch[x][1]].a[0][1],s[ch[x][1]].a[1][1]);
				g[x].a[0][0] += max(a0,a1);
				g[x].a[1][0] += max(a0,a1);
				g[x].a[0][1] += a0;
			}
			if(y){
				int a0 = max(s[y].a[0][0],s[y].a[1][0]),
					a1 = max(s[y].a[0][1],s[y].a[1][1]);
				g[x].a[0][0] -= max(a0,a1);
				g[x].a[1][0] -= max(a0,a1);
				g[x].a[0][1] -= a0;
			}
			ch[x][1] = y , upd(x);
		}
		return y;
	}
}
using namespace LCT;
int info[maxn],Prev[maxn<<1],to[maxn<<1],cnt_e;
void Node(int u,int v){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v; }

void dfs(int now,int ff){
	fa[now] = ff , g[now].a[0][0] = 0 , 
	g[now].a[0][1] = val[now] , g[now].a[1][0] = 0 , g[now].a[1][1] = -inf;
	for(int i=info[now];i;i=Prev[i])
		if(to[i]!=ff){
			dfs(to[i],now);
			int a0 = max(s[to[i]].a[0][0],s[to[i]].a[1][0]),
				a1 = max(s[to[i]].a[0][1],s[to[i]].a[1][1]);
			g[now].a[0][0] += max(a0,a1);
			g[now].a[1][0] += max(a0,a1);
			g[now].a[0][1] += a0;
		}
	upd(now);
	/*printf("%d\n",now);
	for(int i=0;i<2;i++)
		for(int j=0;j<2;j++)
			printf("s[%d][%d] = %d\n",i,j,s[now].a[i][j]);*/
}

int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%d",&val[i]);
	for(int i=1;i<n;i++){
		int u,v;
		scanf("%d%d",&u,&v);
		Node(u,v),Node(v,u);
	}
	dfs(1,0);
	for(int i=1;i<=m;i++){
		int x,y;scanf("%d%d",&x,&y);
		access(x),splay(x);
		g[x].a[0][1] += y - val[x];
		val[x] = y;
		upd(x);
		printf("%d\n",max(max(s[x].a[0][0],s[x].a[0][1]),max(s[x].a[1][0],s[x].a[1][1])));
	}
}

全局平衡二叉树:

#include<bits/stdc++.h>
#define maxn 1000006
#define inf 0x3f3f3f3f
#define il inline
#define pa fa[x]
using namespace std;

char cb[1<<18],*cs=cb,*ct=cb,wb[35000005],*wt=wb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<18,stdin),cs==ct)?0:*cs++)
void read(int &res){
	char ch;bool f=0;
	for(;!isdigit(ch=getc());) if(ch=='-') f=1;
	for(res=ch-'0';isdigit(ch=getc());res=res*10+ch-'0');
	if(f) res = -res;
}

inline void write(int x){
	int p[12],len=0;//x>=0
	while(x) p[++len]=x%10,x/=10;
	if(!len) *wt++='0';
	else while(len) *wt++=p[len--]+'0';
}

struct mat{
	int a,b,c,d;
	mat (int p=-inf){ a = d = p , b = c = -inf; }
	mat operator *(const mat &B)const{
		mat ret;
		ret.a = max(a+B.a,b+B.c);
		ret.b = max(a+B.b,b+B.d);
		ret.c = max(c+B.a,d+B.c);
		ret.d = max(c+B.b,d+B.d);
		return ret;
	}
}f[maxn],g[maxn];

int info[maxn],Prev[maxn<<1],to[maxn<<1],cnt_e;
void Node(int u,int v){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v; }

int n,m,rt;
int fa[maxn],ch[maxn][2],v[maxn];
int isr(int x){ return ch[pa][0] != x && ch[pa][1] != x; }

int siz[maxn],son[maxn];

void dfs1(int u,int ff){
	siz[u] = 1;
	for(int i=info[u],v;i;i=Prev[i])
		if((v=to[i]) != ff){
			dfs1(v,u);
			siz[u]+=siz[v];
			if(son[u] == 0 || siz[v] > siz[son[u]]) son[u] = v;
		}
}
int ar[maxn];
il void upd(int u){ f[u] = f[ch[u][1]] * g[u] * f[ch[u][0]]; }
int Build(int l,int r){
	if(l>r) return 0;
	int L=l,R=r,mid;
	for(;L<R;){
		mid = (L+R+1) >> 1;
		if((siz[ar[mid]] - siz[ar[r+1]]) * 2 >= (siz[ar[l]]-siz[ar[r+1]])) L = mid;
		else R = mid - 1;
	}
	fa[ch[ar[L]][0] = Build(l,L-1)] =  ar[L] , fa[ch[ar[L]][1] = Build(L+1,r)] = ar[L] , fa[0] = 0;
	upd(ar[L]);
	return ar[L];
}
void dfs2(int u,int ff){
	for(int p=u,e=ff;p;p=son[e=p]) 
		for(int i=info[p];i;i=Prev[i]) 
			if(to[i] != e && to[i] != son[p])
				dfs2(to[i],p);
	int len = 0;
	for(int p=u;p;p=son[p]) ar[++len] = p; ar[len+1] = 0;
	int w;
	fa[w = Build(1,len)] = ff;
	if(!ff) rt = w;
	if(ff){
		int a0 = max(f[w].a,f[w].c) , a1 = max(f[w].b,f[w].d);
		g[ff].a+=max(a0,a1),g[ff].b+=a0,g[ff].c+=max(a0,a1);
	}
}

int main(){
	read(n),read(m);
	for(int i=1;i<=n;i++) read(v[i]),g[i].a=g[i].c=0,g[i].d=-inf,g[i].b=v[i];
	g[0] = f[0] = mat(0);
	for(int i=1,u,y;i<n;i++) read(u),read(y),Node(u,y),Node(y,u);
	dfs1(1,0),dfs2(1,0);
	for(int lst=0,x,y;m--;){
		read(x),read(y);x^=lst;
		g[x].b += y - v[x] , v[x] = y;
		for(;x;x=pa){
			if(isr(x) && pa){
				int a0 = max(f[x].a,f[x].c) , a1 = max(a0,max(f[x].b,f[x].d));
				g[pa].a-=a1,g[pa].b-=a0,g[pa].c-=a1;
			}
			upd(x);
			if(isr(x) && pa){
				int a0 = max(f[x].a,f[x].c) , a1 = max(a0,max(f[x].b,f[x].d));
				g[pa].a+=a1,g[pa].b+=a0,g[pa].c+=a1;
			}
		}
		write(lst=max(f[rt].a,max(f[rt].b,max(f[rt].c,f[rt].d)))),*wt++='\n';
	}
	fwrite(wb,wt-wb,1,stdout);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值