zoukankan      html  css  js  c++  java
  • [luogu 4719][模板]动态dp

    传送门

    Solution


    • (f_{i,0}) 表示以i节点为根的子树内,不选i号节点的最大独立集
    • (f_{i,1})表示以i节点为根的子树内,选i号节点的最大独立集
    • (g_{i,0}) 表示以i节点为根的子树内,不选i号节点,不算它的重节点子树的最大独立集
    • (g_{i,1}) 表示以i节点为根的子树内,选i号节点,不算它的重节点子树的最大独立集

    把矩阵乘法的加法改成max,乘法改成加法,仍然符合结合律。

    先进行树链剖分,对于同一条链上的点,我们的更新可以写成如下的矩阵乘法:

    [ left[ egin{matrix} g_{i,0} & g_{i,0} \ g_{i,1} & 0 end{matrix} ight] left[ egin{matrix} f_{i-1,0}\ f_{i-1,1} end{matrix} ight] = left[ egin{matrix} f_{i,0}\ f_{i,1} end{matrix} ight] ]

    矩阵的右下角是0,但是显然并不影响正确性


    用线段树维护区间乘积,每次修改在当前节点到根的路径上进行。

    1. 先单点修改当前点的g值
    2. 用区间乘法算出top节点的f值
    3. 更新top节点的父亲节点的g值
    4. 重复以上操作,直至到根节点


    #include<bits/stdc++.h>
    #define ll long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    inline int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    	return x*f;
    }
    #define MN 100005
    int n,m,v[MN];
    struct edge{int to,nex;}e[MN<<1];
    int hr[MN],en;
    inline void ins(int f,int t)
    {
    	e[++en]=(edge){t,hr[f]};hr[f]=en;
    	e[++en]=(edge){f,hr[t]};hr[t]=en;
    }
    int mx[MN],siz[MN],top[MN],fa[MN];
    void dfs1(int x,int f)
    {
    	siz[x]=1;fa[x]=f;register int i;
    	for(i=hr[x];i;i=e[i].nex)if(f^e[i].to)
    	{
    		dfs1(e[i].to,x);siz[x]+=siz[e[i].to];
    		if(siz[e[i].to]>siz[mx[x]]) mx[x]=e[i].to;
    	}
    }
    void dfs2(int x,int f,int tp)
    {   
    	top[x]=tp;if(mx[x]) dfs2(mx[x],x,tp);
    	register int i;
    	for(i=hr[x];i;i=e[i].nex)if((e[i].to^f)&&(e[i].to^mx[x])) dfs2(e[i].to,x,e[i].to);
    }
    struct matrix
    {
    	ll a[2][2];
    	matrix(){memset(a,0,sizeof a);}
    	matrix operator * (const matrix &b) const
    	{
    		register matrix c;register int i,j,k;
    		for(i=0;i<2;++i)for(j=0;j<2;j++)for(k=0;k<2;++k)
    		c.a[i][j]=max(c.a[i][j],b.a[i][k]+a[k][j]);
        	return c;
    	}
    }t[MN<<2],Ans;
    ll g[MN][2],f[MN][2];
    int pos[MN],id[MN],dind,st[MN];
    void init(int x,int F)
    {
    	register int i;g[x][1]=(ll)v[x];
    	for(i=hr[x];i;i=e[i].nex)
    	if((e[i].to^F)&&(e[i].to^mx[x]))
    	{
    		init(e[i].to,x);
    		g[x][0]+=max(f[e[i].to][0],f[e[i].to][1]);
    		g[x][1]+=f[e[i].to][0];
    	}
    	f[x][0]=g[x][0];f[x][1]=g[x][1];
    	if(mx[x])
    	{
    		init(mx[x],x);
    		f[x][0]+=max(f[mx[x]][0],f[mx[x]][1]);
    		f[x][1]+=f[mx[x]][0];
    	}
    	pos[x]=++dind;id[dind]=x;
    	if(st[top[x]]==0) st[top[x]]=dind;
    }
    #define mid (l+r>>1)
    void build(int k,int l,int r)
    {
    	if(l==r)
    	{
    		t[k].a[0][0]=t[k].a[0][1]=g[id[l]][0];
    		t[k].a[1][0]=g[id[l]][1];t[k].a[1][1]=0ll;
    		return;
    	}
    	build(k<<1,l,mid);build(k<<1|1,mid+1,r);
    	t[k]=t[k<<1]*t[k<<1|1];
    }
    void Modify(int k,int l,int r,int x)
    {
    	if(l==r)
    	{
    		t[k].a[0][0]=t[k].a[0][1]=g[id[l]][0];
    		t[k].a[1][0]=g[id[l]][1];t[k].a[1][1]=0ll;
    		return;
    	}
    	if(x<=mid) Modify(k<<1,l,mid,x);
    	else Modify(k<<1|1,mid+1,r,x);
    	t[k]=t[k<<1]*t[k<<1|1];
    }
    matrix query(int k,int l,int r,int a,int b)
    {
    	if(l==a&&r==b) return t[k];
    	if(b<=mid) return query(k<<1,l,mid,a,b);
    	if(a>mid) return query(k<<1|1,mid+1,r,a,b);
    	return query(k<<1,l,mid,a,mid)*query(k<<1|1,mid+1,r,mid+1,b);
    }
    ll Que()
    {
    	Ans=query(1,1,n,st[1],pos[1]);
    	return max(Ans.a[0][0],Ans.a[1][0]); 
    }
    inline void change(int x,ll add)
    {
    	g[x][1]+=add;
    	while(x!=0){
    		Modify(1,1,n,pos[x]);
    		matrix tmp=query(1,1,n,st[top[x]],pos[top[x]]);
    		ll f0=tmp.a[0][0],f1=tmp.a[1][0];
    		if(top[x]!=1){
    			g[fa[top[x]]][1]+=f0-f[top[x]][0];
    			g[fa[top[x]]][0]+=max(f1,f0)-max(f[top[x]][0],f[top[x]][1]); 
    		}
    		f[top[x]][0]=f0;f[top[x]][1]=f1;
    		x=fa[top[x]];
    	}
    }
    int main()
    {
    	n=read(),m=read();
    	register int i,j;
    	for(i=1;i<=n;i++) v[i]=read();
    	for(i=1;i<n;i++) ins(read(),read());
    	dfs1(1,0);dfs2(1,0,1);init(1,0);build(1,1,n);
    	while(m--)
    	{
    		i=read();j=read();
    		change(i,j-v[i]);v[i]=j;
    		printf("%lld
    ",Que());
    	}
    	return 0;
    }
    





    Blog来自PaperCloud,未经允许,请勿转载,TKS!

  • 相关阅读:
    JS,Jquery获取各种屏幕的宽度和高度
    mysql存储html代码之导出后无法导入问题
    php之简单socket编程
    php单点登录SSO(Single Sign On)的解决思路
    php读取邮件
    YII框架的依赖注入容器
    YII框架的行为
    YII框架的事件机制
    YII框架的模块化技术
    mysql的索引
  • 原文地址:https://www.cnblogs.com/PaperCloud/p/9992924.html
Copyright © 2011-2022 走看看