把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

洛谷P4719 【模板】"动态 DP"&动态树分治

日常懵逼

先不考虑修改,就是一个很基础的没有上司的舞会。

定义状态\(f[i][0/1]\)表示以\(i\)为根且 不选/选 \(i\)的最大权独立集

显然有转移:

\(f[u][0]=\sum max(f[v][0],f[v][1])\)

\(f[u][1]=\sum f[v][0] + a[u]\)

考虑修改时,只会对她上面的链上的节点产生影响。

由于树可能会退化成一条链,那么修改一次更新的时间复杂度就是\(O(n)\),不可接受。

所以需要用重链剖分。

重链剖分有以下性质能够保证快速修改:
1.每个点到根的路径上,最多经过\(log(n)\)条轻边,那么重链最多\(log(n)\)条,保证时间复杂度

2.重链剖分中,一条重链在剖出的\(dfn\)上是连续的一段区间,保证可以用数据结构维护,能够快速转移。

3.每条重链的链尾都是叶节点,而且只有叶节点没有重儿子,保证了状态转移方向。

我们先做一个树剖,然后一条重链,一条重链地进行\(dp\)

然后设\(g[i][0/1]\)表示只考虑轻儿子的\(dp\)

有如下转移:

\(f[i][0]=max(f[hson][0],f[hson][1])+g[i][0]\)

\(f[i][1]=f[hson][0]+g[i][1]\)

然后可以写出矩阵的形式:

\[\begin{bmatrix} f[i][0] \\ f[i][1] \\ \end{bmatrix} = \begin{bmatrix} g[i][0] &g[i][0] \\ g[i][1] & -∞ \\ \end{bmatrix} \times \begin{bmatrix} f[hson][0] \\ f[hson][1] \\ \end{bmatrix} \]

然后就可以树剖+线段树维护,修改时改重链\(f[]\)链顶\(g[]\)就可以了。

#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<iostream>
#include<cstdio>
using namespace std;
#define N 100005
#define INF 0x3f3f3f3f
#define LL long long
int rd()
{
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48); c=getchar();}
	return f*x;
}
int n;
struct Matrix{
	int m[3][3];
	int* operator [](int i){ return m[i]; }
};
Matrix operator * (Matrix a,Matrix b)
{
	Matrix c;
	for(int i=1;i<=2;i++)
		for(int j=1;j<=2;j++)
			c[i][j]=-INF;
	for(int i=1;i<=2;i++)
		for(int k=1;k<=2;k++)
			for(int j=1;j<=2;j++)
				c[i][j]=max(c[i][j],a[i][k]+b[k][j]);
	return c;
}
Matrix tree[N<<2],g[N];
vector<int>G[N];
int a[N],fat[N],siz[N],hson[N],dep[N];
int tp[N],ed[N],dfn[N],tid[N],dfc;
int f[N][2];//f[i][1]以i为根且i选的最大权独立集 f[i][0]不选i 
void dfs(int u,int fa)
{
	int mx=0;
	fat[u]=fa;
	siz[u]=1;
	for(int i=0;i<G[u].size();i++)
	{
		int v=G[u][i];
		if(v==fa) continue;
		dfs(v,u);
		siz[u]+=siz[v];
		if(siz[v]>mx)
			mx=siz[v],hson[u]=v;
	}
}
void dfs2(int u,int Top)
{
	dfc++;
	dfn[u]=dfc;
	tid[dfn[u]]=u;
	tp[u]=Top;
	ed[tp[u]]=dfn[u];
	f[u][0]=g[u][1][1]=0;
	f[u][1]=g[u][2][1]=a[u];
	if(hson[u])
	{
		dfs2(hson[u],Top);
		f[u][1]+=f[hson[u]][0];
		f[u][0]+=max(f[hson[u]][0],f[hson[u]][1]);
	}
	for(int i=0;i<G[u].size();i++)
	{
		int v=G[u][i];
		if(v==fat[u]||v==hson[u]) continue;
		dfs2(v,v);
		g[u][2][1]+=f[v][0],g[u][1][1]+=max(f[v][0],f[v][1]);
		f[u][1]+=f[v][0],f[u][0]+=max(f[v][0],f[v][1]);
	}
	g[u][1][2]=g[u][1][1];
}
void PushUp(int i)
{
	tree[i]=tree[i<<1]*tree[i<<1|1];
}
void Build(int i,int l,int r)
{
	if(l==r)
	{
		tree[i]=g[tid[l]];
		return ;
	}
	int mid=(l+r)>>1;
	Build(i<<1,l,mid);
	Build(i<<1|1,mid+1,r);
	PushUp(i);
}
void Update(int i,int l,int r,int pos)
{
	if(l==r)
	{
		tree[i]=g[tid[pos]];
		return ;
	}
	int mid=(l+r)>>1;
	if(pos<=mid) Update(i<<1,l,mid,pos);
	else Update(i<<1|1,mid+1,r,pos);
	PushUp(i);
} 
Matrix Query(int i,int l,int r,int ql,int qr)
{
	if(ql<=l&&r<=qr) return tree[i];
	int mid=(l+r)>>1;
	if(qr<=mid) return Query(i<<1,l,mid,ql,qr);
	else if(ql>mid) return Query(i<<1|1,mid+1,r,ql,qr);
	return Query(i<<1,l,mid,ql,qr)*Query(i<<1|1,mid+1,r,ql,qr);
}
void Modify(int u,int val)
{
	g[u][2][1]+=val-a[u],a[u]=val;
	while(u)
	{
		Matrix x=Query(1,1,n,dfn[tp[u]],ed[tp[u]]);
		Update(1,1,n,dfn[u]);
		Matrix y=Query(1,1,n,dfn[tp[u]],ed[tp[u]]);
		u=fat[tp[u]];
		g[u][1][1]+=max(y[1][1],y[2][1])-max(x[1][1],x[2][1]);
		g[u][1][2]=g[u][1][1];
		g[u][2][1]+=y[1][1]-x[1][1]; 
	}
}
int main()
{
	n=rd();int Q=rd();
	for(int i=1;i<=n;i++)
		a[i]=rd();
	for(int i=1;i<=n-1;i++)
	{
		int u=rd(),v=rd();
		G[u].push_back(v);
		G[v].push_back(u);
	}
	dfs(1,0);
	dfs2(1,1);
	Build(1,1,n);
	while(Q--)
	{
		int u=rd(),val=rd();
		Modify(u,val);
		Matrix ans=Query(1,1,n,1,ed[1]);
		printf("%d\n",max(ans[1][1],ans[2][1]));
	}
    return 0;
}
posted @ 2020-07-29 11:08  Starlight_Glimmer  阅读(144)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end