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;
    }
    
  • 相关阅读:
    (4.25)Sqlserver中 登录用户只能看到自己拥有权限的库
    【查阅】mysql配置文件/参数文件重要参数笔录(my.cnf)
    【监控笔记】【2.5】DML(CDC)、DDL(DDL触发器)跟踪数据更改,数据库审计
    SQL Server 2008中的CDC(Change Data Capture)功能使用及释疑
    【监控笔记】【2.4】SQL Server中的 Ring Buffer 诊断各种系统资源压力情况
    【监控笔记】【2.3】扩展事件——慢查询SQL(执行超过3S的SQL)
    【监控笔记】【2.2】扩展事件——死锁监控
    最小配置启动SQL SERVER,更改SQL Server最大内存大小导致不能启动的解决方法
    【监控笔记】【2.1】扩展事件
    【扩展事件】跟踪超过3秒的SQL
  • 原文地址:https://www.cnblogs.com/mleautomaton/p/10263735.html
Copyright © 2011-2022 走看看