洛谷5024 保卫王国 (动态dp)

qwq非正解。
但是能跑过。
1e5 log方还是很稳的啊

首先,考虑最普通的 d p dp dp
d p 1 [ x ] [ 0 ] 表 示 不 选 这 个 点 , d p 1 [ x ] [ 1 ] 表 示 选 这 个 点 的 最 大 最 小 花 费 dp1[x][0]表示不选这个点,dp1[x][1]表示选这个点的最大最小花费 dp1[x][0]dp1[x][1]
那么
d p 1 [ x ] [ 0 ] = ∑ d p [ p ] [ 1 ] dp1[x][0]=\sum dp[p][1] dp1[x][0]=dp[p][1]
d p 1 [ x ] [ 1 ] = ∑ m i n ( d p [ p ] [ 1 ] , d p [ p ] [ 0 ] ) + v a l [ x ] dp1[x][1]=\sum min(dp[p][1],dp[p][0])+val[x] dp1[x][1]=min(dp[p][1],dp[p][0])+val[x]

根据套路,我们要树链剖分+改变 d p dp dp数组,我们令 f [ x ] f[x] f[x]表示忽略重儿子的 d p dp dp值,用 g g g表示正常的 d p dp dp值的话

那么不难发现转移矩阵应该是

{g[p][0],g[p][1]} 

乘上

inf f[x][1]
f[x][0] f[x][1]

等于

g[x][0] g[x][1]

qwq
然后其他的就是动态dp的部分了

但是需要注意的一个地方是。
你如果通过写一个类似的 m o d i f y modify modify

void modify(int x,Ju y)
{
	update(1,1,n,newnum[x],y);
	for (int now=top[x];now!=1;now=top[now])
	{
		int faa = fa[now];
		Ju ymh = query(1,1,n,newnum[faa],newnum[faa]);
		Ju lyf = query(1,1,n,newnum[now],newnum[tail[top[now]]]);
		ymh.a[1][2]+=min(lyf.a[1][2],lyf.a[1][1]) - min(pre[now].a[1][2],pre[now].a[1][1]);
		ymh.a[2][2]=ymh.a[1][2];
		ymh.a[2][1]+=lyf.a[1][2]-pre[now].a[1][2];
		if (faa==tail[top[faa]]) ymh.a[1][1]=ymh.a[2][1];
		update(1,1,n,newnum[faa],ymh);
		pre[now]=lyf;
		now = fa[now];
	}
}

你需要 m o d i f y modify modify三次,才可以。因为你第一次 m o d i f y modify modify实际上是基于另一个不还原的前提下来还原第一个,但是实际上,我们是要求在另一个还原过的基础上还原第一个。

但是如果你用如下的函数进行还原的话

void wei(int x)
{
	update(1,1,n,newnum[x],ymh[x]);
	for (int now = top[x];now!=1;now=top[now])
	{
		int faa = fa[now];
		update(1,1,n,newnum[faa],ymh[faa]);
		pre[now]=bre[now];
		now=fa[now];
	}
}

直接给代码

// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<map>
#include<set>
#define pb push_back
#define mk make_pair
#define ll long long
#define lson ch[x][0]
#define rson ch[x][1]

using namespace std;

inline int read()
{
  int x=0,f=1;char ch=getchar();
  while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
  while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  return x*f;
}

const int maxn = 2e5+1e2;
const int maxm = 2*maxn;
const ll inf = 1e18;

struct Ju{
	int x,y;
	ll a[3][3];
	Ju operator * (Ju b)
	{
		Ju ans;
		ans.x=2;
		ans.y=2;
		memset(ans.a,127/3,sizeof(ans.a));
		for (int i=1;i<=2;i++)
		{
			for (int j=1;j<=2;j++)
			  for (int k=1;k<=2;k++)
			  {
			  	 ans.a[i][j]=min(ans.a[i][j],a[i][k]+b.a[k][j]);
			  }
		}
		return ans;
	}
};

Ju f[4*maxn];
Ju pre[maxn];
int point[maxn],nxt[maxm],to[maxm];
int cnt,n,m,q;
ll val[maxn],dp1[maxn][2],dp[maxn][2];
Ju ymh[maxn];
int fa[maxn],size[maxn],son[maxn],back[maxn],newnum[maxn];
int tail[maxn],top[maxn];

void addedge(int x,int y)
{
	nxt[++cnt]=point[x];
	to[cnt]=y;
	point[x]=cnt;
}

void up(int root)
{
	f[root]=f[2*root+1]*f[2*root]; 
}

Ju bre[maxn];

void build(int root,int l,int r)
{
	if (l==r)
	{
		int now = back[l];
		f[root].x=f[root].y=2;
		if (tail[top[now]]==now)
		{
			f[root].a[1][1]=dp[now][0];
			f[root].a[1][2]=dp[now][1];
			f[root].a[2][1]=f[root].a[1][1];
			f[root].a[2][2]=f[root].a[1][2];
		}
		else
		{
		  f[root].a[1][1]=inf;
		  f[root].a[1][2]=dp[now][1];
		  f[root].a[2][1]=dp[now][0];
		  f[root].a[2][2]=dp[now][1];
	    }
	    ymh[now]=f[root];
	    return;
	}
	int mid = l+r >> 1;
    build(2*root,l,mid);
	build(2*root+1,mid+1,r);
	up(root); 
}

void update(int root,int l,int r,int x,Ju p)
{
	if(l==r) 
	{
		f[root]=p;
		return;
	}
	int mid = l+r >> 1;
	if (x<=mid) update(2*root,l,mid,x,p);
	else update(2*root+1,mid+1,r,x,p);
	up(root);
}

Ju query(int root,int l,int r,int x,int y)
{
	if (x<=l && r<=y) return f[root];
	int mid = l+r>>1;
    if (y<=mid) return query(2*root,l,mid,x,y);
    if (x>mid) return query(2*root+1,mid+1,r,x,y);
    return query(2*root+1,mid+1,r,x,y)*query(2*root,l,mid,x,y);
}


void dfs1(int x,int faa)
{
	size[x]=1;
	int maxson=-1;
	for (int i=point[x];i;i=nxt[i])
	{
		int p = to[i];
		if (p==faa) continue;
		fa[p]=x;
		dfs1(p,x);
		size[x]+=size[p];
		if (size[p]>maxson)
		{
			maxson=size[p];
			son[x]=p;
		}
	}
} 

int tot;

void dfs2(int x,int chain)
{
	top[x]=chain;
	tail[chain]=x;
	newnum[x]=++tot;
	back[tot]=x;
	if (!son[x]) return;
	dfs2(son[x],chain);
	for (int i=point[x];i;i=nxt[i])
	{
		int p = to[i];
		if (!newnum[p]) dfs2(p,p);
	}
}

void solve(int x,int fa)
{
	dp1[x][1]=dp[x][1]=val[x];
	for (int i=point[x];i;i=nxt[i])
	{
		int p = to[i];
		if (p==fa) continue;
		solve(p,x); 
		dp1[x][0]=dp1[x][0]+dp1[p][1];
		dp1[x][1]=dp1[x][1]+min(dp1[p][0],dp1[p][1]);
		if (p!=son[x])
		{
			dp[x][0]=dp[x][0]+dp1[p][1];
			dp[x][1]=dp[x][1]+min(dp1[p][0],dp1[p][1]);
		}
	}
}

int uu;

void modify(int x,Ju y)
{
	update(1,1,n,newnum[x],y);
	for (int now=top[x];now!=1;now=top[now])
	{
		int faa = fa[now];
		Ju ymh = query(1,1,n,newnum[faa],newnum[faa]);
		Ju lyf = query(1,1,n,newnum[now],newnum[tail[top[now]]]);
		ymh.a[1][2]+=min(lyf.a[1][2],lyf.a[1][1]) - min(pre[now].a[1][2],pre[now].a[1][1]);
		ymh.a[2][2]=ymh.a[1][2];
		ymh.a[2][1]+=lyf.a[1][2]-pre[now].a[1][2];
		if (faa==tail[top[faa]]) ymh.a[1][1]=ymh.a[2][1];
		update(1,1,n,newnum[faa],ymh);
		pre[now]=lyf;
		now = fa[now];
	}
}

void wei(int x)
{
	update(1,1,n,newnum[x],ymh[x]);
	for (int now = top[x];now!=1;now=top[now])
	{
		int faa = fa[now];
		update(1,1,n,newnum[faa],ymh[faa]);
		pre[now]=bre[now];
		now=fa[now];
	}
}
signed main()
{
  n=read();m=read(),uu=read(); 
  for (int i=1;i<=n;i++) val[i]=read();
  for (int i=1;i<n;i++)
  {
  	int x=read(),y=read();
  	addedge(x,y);
  	addedge(y,x);
  }
  dfs1(1,0);
  dfs2(1,1);
  solve(1,0);
  build(1,1,n);
  for (int i=1;i<=n;i++)
  {
  	 pre[i]=query(1,1,n,newnum[i],newnum[tail[top[i]]]);
  	// cout<<i<<" "<<pre[i].a[1][1]<<" "<<pre[i].a[1][2]<<endl;
  	bre[i]=pre[i];
  }
  for (int i=1;i<=m;i++)
  {
  	int a=read(),x=read(),b=read(),y=read();
  	Ju tmp = query(1,1,n,newnum[a],newnum[a]);
  	if (x==0)
	{
	  if (a!=tail[top[a]])
	  {
	    tmp.a[1][2]=inf;
	    tmp.a[2][2]=inf; 
	  }
	  else
	  {
	  	 tmp.a[1][2]=inf;
	  	 tmp.a[2][2]=inf;
	  }
	} 
	else
	{
		if (a!=tail[top[a]])
		tmp.a[2][1]=inf;
		else tmp.a[1][1]=tmp.a[2][1]=inf;
	}
	modify(a,tmp);
	tmp = query(1,1,n,newnum[b],newnum[b]);
	if (y==0)
	{
		tmp.a[1][2]=tmp.a[2][2]=inf;
	}
	else
	{
		if (b!=tail[top[b]])
		tmp.a[2][1]=inf;
		else tmp.a[1][1]=tmp.a[2][1]=inf;
	}
	modify(b,tmp);
    Ju now = query(1,1,n,newnum[1],newnum[tail[top[1]]]);
    ll ptx = min(now.a[1][1],now.a[1][2]);
    if (ptx>=inf) ptx=-1;
    cout<<ptx<<"\n";
    modify(a,ymh[a]);
    modify(b,ymh[b]);
    //wei(a);
    //wei(b);
    modify(a,ymh[a]);
  } 
  return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值