zoukankan      html  css  js  c++  java
  • 【洛谷4719】 动态dp(树链剖分,dp,矩阵乘法)

    前言

    其实我只是为了过掉模板而写的ddp,实际应用被吊着锤

    Solution

    并不想写详细的过程

    一句话过程:将子树中轻儿子的贡献挂到这个点上面来

    详细版:(引用yyb)

    总结一下的话,大致的过程是这样子的:首先我们考虑我们的转移方程,发现能够将其改写为矩乘的形式,那么我们首先将转移改为矩乘。我们把轻链和重链的转移分开考虑。这样子想,我们的重链被我们单独拎了出来,每个重链上都挂上了若干轻儿子,显然轻儿子对于重链上的独立集的选择是没有影响的,换而言之,如果轻儿子的贡献考虑完之后,那么等价于链上每个点选或者不选有一个权值,求最大独立集。而对于链上的这个东西,是可以直接用线段数维护矩阵支持修改和查询的,那么这题就只需要这么做就好了。即只修改这个点到达根节点上的所有轻链对于父亲的贡献,对于重儿子的贡献先暂时不考虑,每次线段树查询矩阵乘积即可求解出每个点的矩阵,就可以快速求解答案了

    代码实现

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>
    #include<algorithm>
    #include<queue>
    #include<set>
    #include<map>
    #include<iostream>
    using namespace std;
    #define ll long long
    #define re register
    #define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
    inline int gi(){
    	int f=1,sum=0;char ch=getchar();
    	while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    	return f*sum;
    }
    const int N=100010;
    const ll Inf=1e18+10;
    int a[N],front[N],nxt[N<<1],to[N<<1],cnt,n,m,dep[N],son[N],siz[N],fa[N],top[N],dfn[N],Time,id[N],bot[N];
    void Add(int u,int v){
    	to[++cnt]=v;nxt[cnt]=front[u];front[u]=cnt;
    }
    struct matrix{
    	ll a[2][2];
    	ll*operator [](int x){return a[x];};
    	matrix operator*(matrix b)const{
    		matrix c;
    		for(int i=0;i<2;i++)
    			for(int j=0;j<2;j++){
    				c[i][j]=0;
    				for(int k=0;k<2;k++)
    					c[i][j]=max(c[i][j],a[i][k]+b[k][j]);
    			}
    		return c;
    	}
    }t[N<<2],tmp[N];
    void dfs1(int u,int f){
    	dep[u]=dep[f]+1;siz[u]=1;fa[u]=f;
    	for(int i=front[u];i;i=nxt[i]){
    		int v=to[i];
    		if(v==f)continue;
    		dfs1(v,u);
    		siz[u]+=siz[v];if(siz[v]>siz[son[u]])son[u]=v;
    	}
    }
    void dfs2(int u,int tp){
    	top[u]=tp;dfn[u]=++Time;id[Time]=u;
    	if(son[u]){dfs2(son[u],tp),bot[u]=bot[son[u]];}
    	else bot[u]=u;
    	for(int i=front[u];i;i=nxt[i]){
    		int v=to[i];
    		if(v==fa[u] || v==son[u])continue;
    		dfs2(v,v);
    	}
    }
    ll f[N][2];
    void dp(int u){
    	f[u][1]=a[u];
    	for(int i=front[u];i;i=nxt[i]){
    		int v=to[i];
    		if(v==fa[u])continue;
    		dp(v);
    		f[u][0]+=max(f[v][1],f[v][0]);
    		f[u][1]+=f[v][0];
    	}
    }
    void build(int o,int l,int r){
    	if(l==r){
    		int u=id[l];int g0=0,g1=a[u];
    		for(int i=front[u];i;i=nxt[i]){
    			int v=to[i];
    			if(v==fa[u] || v==son[u])continue;
    			g0+=max(f[v][1],f[v][0]);g1+=f[v][0];
    		}
    		tmp[l]=t[o]=(matrix){g0,g0,g1,-Inf};
    		return;
    	}
    	int mid=(l+r)>>1;
    	build(o<<1,l,mid);build(o<<1|1,mid+1,r);
    	t[o]=t[o<<1]*t[o<<1|1];
    }
    //------------以上是dp+树剖-----------------------------------------------
    void Modify(int o,int l,int r,int p){
    	if(l==r){t[o]=tmp[l];return;}
    	int mid=(l+r)>>1;
    	if(p<=mid)Modify(o<<1,l,mid,p);
    	else Modify(o<<1|1,mid+1,r,p);
    	t[o]=t[o<<1]*t[o<<1|1];
    }
    matrix query(int o,int l,int r,int posl,int posr){
    	if(posl==l && posr==r)return t[o];
    	int mid=(l+r)>>1;
    	if(mid>=posr)return query(o<<1,l,mid,posl,posr);
    	else if(mid<posl)return query(o<<1|1,mid+1,r,posl,posr);
    	return query(o<<1,l,mid,posl,mid)*query(o<<1|1,mid+1,r,mid+1,posr);
    }
    matrix ask(int x){return query(1,1,n,dfn[top[x]],dfn[bot[x]]);}
    void Modify(int u,int w){
    	tmp[dfn[u]][1][0]+=w-a[u];a[u]=w;
    	while(u){
    		matrix a=ask(top[u]);Modify(1,1,n,dfn[u]);
    		matrix b=ask(top[u]);
    		u=fa[top[u]];if(!u)break;
    		tmp[dfn[u]][0][1]=(tmp[dfn[u]][0][0]+=max(b[0][0],b[1][0])-max(a[0][0],a[1][0]));
    		tmp[dfn[u]][1][0]+=b[0][0]-a[0][0];
    	}
    }
    int main(){
    	n=gi();m=gi();
    	for(int i=1;i<=n;i++)a[i]=gi();
    	for(int i=1;i<n;i++){int u=gi(),v=gi();Add(u,v);Add(v,u);}
    	dfs1(1,0);dfs2(1,1);dp(1);build(1,1,n);
    	matrix t;
    	while(m--){
    		int u=gi(),x=gi();
    		Modify(u,x);
    		t=ask(1);
    		printf("%lld
    ",max(t[0][0],t[1][0]));
    	}
    	return 0;
    }
    
  • 相关阅读:
    Balance的数学思想构造辅助函数
    1663. Smallest String With A Given Numeric Value (M)
    1680. Concatenation of Consecutive Binary Numbers (M)
    1631. Path With Minimum Effort (M)
    1437. Check If All 1's Are at Least Length K Places Away (E)
    1329. Sort the Matrix Diagonally (M)
    1657. Determine if Two Strings Are Close (M)
    1673. Find the Most Competitive Subsequence (M)
    1641. Count Sorted Vowel Strings (M)
    1679. Max Number of K-Sum Pairs (M)
  • 原文地址:https://www.cnblogs.com/mleautomaton/p/10263735.html
Copyright © 2011-2022 走看看