首页 > 其他分享 >P6021 洪水 题解

P6021 洪水 题解

时间:2024-01-15 17:46:02浏览次数:28  
标签:mat val P6021 题解 tp int dfn bmatrix 洪水

请先完成 ddp模板

一个 ddp 讲解视频


Part0:题意解释

感觉题面太阴间了。所以解释一下:

C x t 表示把 \(x\) 结点的权值改为 \(t\).

Q x :把 \(x\) 子树中一些结点删去,使得 \(x\) 与 \(x\) 子树内所有叶子结点不连通。求 删去的结点权值和 的最小值。

Part1:先不考虑修改操作

发现原题变成了一道简单的树形dp问题

令 \(f_u\) 表示 使 \(u\) 与其子树内叶子节点都不连通的最小代价。\(val_u\) 是 \(u\) 的权值

容易得到 \(f_u=\min(val_u,\sum \limits_{v \in son_u} f_v)\)

叶子节点特判:\(f_u=val_u\)

这样每一次修改操作后重新更新 \(f_u\) 的时间复杂度是 \(O(nm)\).

Part3:ddp

注意到,每一次修改某一个结点 \(x\) 的 \(val_x\) 时,\(f_u\) 会被修改的 \(u\) 只有 \(x\) 到根节点这一条链上的结点。所以就可以考虑ddp了。

根据ddp的套路,考虑把重儿子和轻儿子拆开。

令 \(s_u\) 为 \(u\)的重儿子。令 \(g_u= \sum \limits_{v \in son_u,v\neq s_u} f_v\).

现在重新写出 \(f\) 的转移方程:\(g_u=\min(val_u,g_u+f_{s_u})\)

根据ddp的套路,现在考虑把原方程转化成矩阵的形式。

先对矩阵乘法做一点改变:令 \(C_{i,j}=\min \limits_k (A_{i,k}+B_{k,j})\)

简单变一下原来的 \(f\) 转移式子:\(g_u=\min(val_u+0,g_u+f_{s_u})\)

可以得到

\[ \begin{bmatrix} g_u & val_u\\0 & \infty \end{bmatrix} * \begin{bmatrix} f_{s_u}\\0 \end{bmatrix} = \begin{bmatrix} f_u\\0 \end{bmatrix} \]

所以,每个结点对应的转移矩阵就是 \(\begin{bmatrix}g_u & val_u\\0 & \infty \end{bmatrix}\).

要求一个点 \(u\) 的 \(f_u\) 时,就只用求 \(dfn_u\) 到 \(ed_u\) 的矩阵乘积。

要修改一个点 \(u\) 的 \(val_u\) 时,在线段树中修改 \(u\) 对应的矩阵,然后求出 \(f_{top_u}\) 的变化值,并修改 \({fa_{top_u}}\) 对应的矩阵。将 \(u\) 赋值为 \({fa_{top_u}}\),再次重复运算,直到到达根节点。

这里有一些注意点:

  1. 为什么要把 \(f_u\) 表示成 \(\begin{bmatrix}f_u\\0 \end{bmatrix}\),而不是 表示成 \(\begin{bmatrix}f_u&0 \end{bmatrix}\) 呢?因为第一种表示方式,是用 \(\begin{bmatrix}f_{s_u}\\0 \end{bmatrix}\)左乘转移矩阵 \(\begin{bmatrix}g_u & val_u\\0 & \infty \end{bmatrix}\) 。而在 dfn 标号中, \(dfn_u=dfn_{s_u}-1\) 。第二种表示方式,是右乘转移矩阵,不方便线段树的维护。ps:模板题中的题解也提到了这个tip。
  2. 叶子结点的矩阵要特殊处理,正常的结点对应的矩阵就是 \(\begin{bmatrix}g_u & val_u\\0 & \infty \end{bmatrix}\) 。但是叶子结点的矩阵要对应成 \(\begin{bmatrix}f_u\\0 \end{bmatrix}\)。可以自行思考一下为什么。

Part4:代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=2e5+5;
int read(){
	int x=0;char c=getchar();bool f=0;
	while(c>'9'||c<'0'){f|=(c=='-');c=getchar();}
	while(c<='9'&&c>='0'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return f?-x:x;
}
void write(ll x){
	if(x<0)	putchar('-');
	if(x>9)	write(x/10);
	putchar(x%10+'0');
}
struct Matrix{
	ll mat[2][2];
	Matrix(){memset(mat,0x3f,sizeof(mat));}
	Matrix operator *(Matrix b){
		Matrix c;
		for(int i=0;i<2;i++){
			for(int j=0;j<2;j++){
				for(int k=0;k<2;k++){
					c.mat[i][j]=min(c.mat[i][j],mat[i][k]+b.mat[k][j]);
				}
			}
		}
		return c;
	}
}v[MAXN<<2];

int n;
ll val[MAXN];
vector<int> G[MAXN];
int fa[MAXN],dfn[MAXN],idfn[MAXN],siz[MAXN],son[MAXN],ed[MAXN],top[MAXN];
Matrix g[MAXN];
ll f[MAXN];
void dfs0(int u){
	siz[u]=1,son[u]=0;
	for(int v:G[u]){
		if(v==fa[u])	continue;
		fa[v]=u;
		dfs0(v);
		siz[u]+=siz[v];
		if(siz[v]>siz[son[u]])	son[u]=v;	
	}
}
void dfs1(int u,int tp){
	dfn[u]=++dfn[0];
	idfn[dfn[0]]=u;
	top[u]=tp;
	ed[tp]=max(ed[tp],dfn[u]);

	if(!son[u]){//特判叶子结点 叶子节点的g=f
		f[u]=val[u];
		g[u].mat[0][0]=val[u];
		g[u].mat[1][0]=0;
		return;
	}
	
	f[u]=0;
	g[u].mat[0][0]=0;
	g[u].mat[0][1]=val[u];
	g[u].mat[1][1]=0;
	
	if(son[u]){
		dfs1(son[u],tp);
		f[u]+=f[son[u]];
	}
	for(int v:G[u]){
		if(v==fa[u]||v==son[u])	continue;
		dfs1(v,v);
		f[u]+=f[v];
		g[u].mat[0][0]+=f[v];
	}
	f[u]=min(f[u],val[u]);
}

#define lc (u<<1)
#define rc (u<<1|1)
void build(int u,int l,int r){
	if(l==r){v[u]=g[idfn[l]];return;}
	int mid=l+r>>1;
	build(lc,l,mid),build(rc,mid+1,r);
	v[u]=v[lc]*v[rc];
}
void change(int u,int l,int r,int pos){
	if(l==r){v[u]=g[idfn[l]];return;}
	int mid=l+r>>1;
	if(pos<=mid)	change(lc,l,mid,pos);
	else	change(rc,mid+1,r,pos);
	v[u]=v[lc]*v[rc];
}
Matrix query(int u,int l,int r,int L,int R){
	if(l>=L&&r<=R)	return v[u];
	int mid=l+r>>1;
	if(R<=mid)	return query(lc,l,mid,L,R);
	else if(L>mid)	return query(rc,mid+1,r,L,R);
	else return query(lc,l,mid,L,R)*query(rc,mid+1,r,L,R);
}
void work1(int u,ll Val){
	if(son[u])	g[u].mat[0][1]+=Val;
	else	g[u].mat[0][0]+=Val;
	val[u]+=Val;
	while(u){
		int tp=top[u];
		Matrix las=query(1,1,n,dfn[tp],ed[tp]);
		change(1,1,n,dfn[u]);
		Matrix now=query(1,1,n,dfn[tp],ed[tp]);
		
		if(!fa[tp])	break;
		g[fa[tp]].mat[0][0]+=now.mat[0][0]-las.mat[0][0];
		u=fa[tp];
	}
}
ll work2(int u){
	Matrix ret=query(1,1,n,dfn[u],ed[top[u]]);
	return ret.mat[0][0];
}
int main(){
	// freopen(".in","r",stdin);
	// freopen(".out","w",stdout);
	n=read();
	for(int i=1;i<=n;i++)	val[i]=1ll*read();
	for(int i=1;i<n;i++){
		int u=read(),v=read();
		G[u].push_back(v),G[v].push_back(u);
	}
	dfs0(1),dfs1(1,1);build(1,1,n);
	int Q=read();
	while(Q--){
		int x,t;
		char op;scanf("\n%c %d",&op,&x);
		if(op=='C'){scanf("%d",&t);work1(x,1ll*t);}
		else	write(work2(x)),putchar('\n');
	}
	return 0;
}

标签:mat,val,P6021,题解,tp,int,dfn,bmatrix,洪水
From: https://www.cnblogs.com/bwartist/p/17965908

相关文章

  • electron安装卡住问题解决
    问题安装electron会卡住,你换镜像,挂梯子都没有用。解决办法自己配置下载electron二进制文件的地址解决步骤npmconfigls进入该配置文件,手动添加ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/electron_mirror=npm.taobao.org这两行重新npminstallele......
  • Codeforces Round 919 (Div. 2)(A~D) 题解
    CodeforcesRound919(Div.2)(A~D)题解A.SatisfyingConstraints题意:给你一些条件让你求出满足条件的整数有多少个。模拟即可。#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;constllMAXN=2e5+5;llTex=1,n;voidAC(){ cin>>n; lll=......
  • element-forge在Linux Centos中打包构建时遇到的异常问题解决方案
    环境:LinuxCentOS8x64electron:27.1.0electron-forge:7.1.0electrondev依赖包"devDependencies":{"@electron-forge/cli":"^7.1.0","@electron-forge/maker-deb":"^7.1.0","@electron-forge/maker-rpm&quo......
  • P10058 Reverse and Rotate题解
    简单题意一共3个操作:rev:将字符串翻转。>\(x\):将后面\(x\)个字母移到前面。<\(x\):将前面\(x\)个字母移到后面。解法解法一看到#1到#3的范围可以打出暴力程序,按题意模拟,时间复杂度\(O(n|S|)\)。预计\(30\)pts。解法二很明显,第二个操作和第三个操作有点像......
  • P9816 少项式复合幂 题解
    题目链接:少项式复合幂注意到题目的模并不是很大,我们考虑两个核心的性质。\(f(f(x))\bmodp=f(f(x)\bmodp)\bmodp\),证明直接代入\(f(x)\)进去得到:\(f(f(x))=a_0\timesf^0(x)+a_1\timesf^1(x)...+a_n\timesf^n(x)\bmodp=\)\[\sum_{i=0}^{n}a_i\timesf^{i}(x)\b......
  • P5501 [LnOI2019] 来者不拒,去者不追 题解
    题目链接:来者不拒,去者不追直接在线查询题目所给的式子是很困难的,我们考虑单点考察贡献。对于一个已经确定的式子,我们发现加入一个数或者删除一个数的贡献如图所示:如图所示,在原有的序列为\((1,2,3)\)当中,我们加入新的\(2\)进去,我们观察到每个数的贡献的变化是这样,比\(2\)......
  • 题解 P7169 [eJOI2020 Day1] Exam
    传送门。题意有两个长度为\(N\)的数列\(A_i\),\(B_i\)。可以对\(A\)数组进行若干次操作,每次可以使\(A_i\)到\(A_j\)中的所有数变成期间的最大值,求最多能使多少个数满足要求。分析显然,要使我们的某一个\(A_x\)变成\(B_x\),至少会包含\(A_{L_x}\)或\(A_{R_x}\),\(L_......
  • P5321 [BJOI2019] 送别 题解--zhengjun
    由于大家的做法需要大量分类讨论和代码量,这里提供一种不怎么分类的,容易实现的做法。首先,由于墙体会随时变化,所以直接对墙体本身维护不是很方便。我们可以牺牲一点常数,对\((i,j)\)建立四个点\(UL_{i,j},UR_{i,j},DL_{i,j},DR_{i,j}\)分别表示\((i-\varepsilon,j-\varepsilo......
  • AT_arc125_c [ARC125C] LIS to Original Sequence 题解
    题目传送门前置知识贪心|构造解法对于任意一个未加入序列\(P\)的数\(x<A_{i}(1\lei\lek-1)\),如果其放在了\(A_{i}\)的前面,会导致最长上升子序列长度加一,从而不符合题目要求。因此我们需要把\(x\)放在\(A_{i}\)后面,同理,为符合题目要求,我们仅选择放最小的那一个......
  • P2198 杀蚂蚁 题解
    题目大意有一条长度为\(n\)个单位长度的路,蚂蚁们要从起点走到终点。蚂蚁们每走\(1\)个单位距离需要\(T\)秒钟。现在,出题人可以在路上修筑\(3\)种防御塔来阻挡蚂蚁的进攻,每个单位距离只能修筑\(1\)座塔,塔的作用分别如下:激光塔:蚂蚁在塔前时每秒会受到\(r\)点伤害。......