首页 > 其他分享 >Living-Dream 系列笔记 第69期

Living-Dream 系列笔记 第69期

时间:2024-07-30 15:32:01浏览次数:6  
标签:Living cur int back 69 Dream 节点 dp dis

复习树形 dp。

树形 dp 定义状态一般套路:令 \(dp_i\) 表示以 \(i\) 为子树的 xxx(要维护的信息),可以有多维,但一定会有这一维。

P2016 & P2014

请查阅往期笔记,此处不再赘述。

P2585

以前是分讨每个节点有几个儿子,然后分别转移。

其实不用分讨,直接将所有节点视作有两个儿子,初始时将它们的贡献设为 \(0\) 就不会有影响了。

然后记住本代码中递归建树是怎么写的。

code
#include<bits/stdc++.h>
using namespace std;

const int N=5e5+5;
string s;
int tot,tree[N<<1][2];
int dp[N][3],f[N][3];

int build(){
	int cur=++tot;
	if(s[cur]=='2')
		tree[cur][0]=build(),
		tree[cur][1]=build();
	else if(s[cur]=='1')
		tree[cur][0]=build();
	return cur; 
}
void dfs(int cur){
	if(!cur) return;
	dp[cur][0]=f[cur][0]=1;
	f[cur][1]=f[cur][2]=0;
	dp[cur][1]=dp[cur][2]=0;
	dfs(tree[cur][0]),dfs(tree[cur][1]);
	dp[cur][0]+=max(dp[tree[cur][0]][1]+dp[tree[cur][1]][2],dp[tree[cur][0]][2]+dp[tree[cur][1]][1]);
	dp[cur][1]+=max(dp[tree[cur][0]][0]+dp[tree[cur][1]][2],dp[tree[cur][0]][2]+dp[tree[cur][1]][0]);
	dp[cur][2]+=max(dp[tree[cur][0]][0]+dp[tree[cur][1]][1],dp[tree[cur][0]][1]+dp[tree[cur][1]][0]);
	f[cur][0]+=min(f[tree[cur][0]][1]+f[tree[cur][1]][2],f[tree[cur][0]][2]+f[tree[cur][1]][1]);
	f[cur][1]+=min(f[tree[cur][0]][0]+f[tree[cur][1]][2],f[tree[cur][0]][2]+f[tree[cur][1]][0]);
	f[cur][2]+=min(f[tree[cur][0]][0]+f[tree[cur][1]][1],f[tree[cur][0]][1]+f[tree[cur][1]][0]);
}

int main(){
	cin>>s,s="#"+s;
	memset(f,0x3f,sizeof f);
	dp[0][0]=dp[0][1]=dp[0][2]=0;
	f[0][0]=f[0][1]=f[0][2]=0;
	int t=build();
	dfs(1);
	int ans1=max({dp[1][0],dp[1][1],dp[1][2]});
	int ans2=min({f[1][0],f[1][1],f[1][2]});
	cout<<ans1<<' '<<ans2;
	return 0;
}

P1131

ZJOI 拿下二杀。

令 \(dp_i\) 表示在 \(i\) 的子树内使得其时态同步所需的最小道具使用次数。

答案显然为 \(\sum dp_i\)(每次使用道具只会改一条边,因此加上所有点)。

一个节点 \(i\) 要使用道具使其时态同步,当且仅当它的子节点 \(j\) 的子树满足时态同步,不然它怎么用道具都是无效的(记住 \(i\) 使用道具只能改变 \(i \to j\) 这一条边)。

令 \(dis_i\) 表示节点 \(i\) 到其子树内距它最远的叶子节点与它的距离。

则有转移:

\[dp_i=dis_i-dis_j-w \]

其中 \(w\) 表示边 \(i \to j\) 的边权。

\(dis_i\) 我们依然可以使用一个 dfs 维护(相当于一个辅助状态)。

初始状态都设 \(0\) 即可。

code
#include<bits/stdc++.h>
#define int long long
using namespace std;

const int N=5e5+5;
int n,s;
struct E{ int v,w; };
vector<E> G[N<<1]; 
int dis[N],dp[N];

void pre(int cur,int fa){
	dis[cur]=0;
	for(auto i:G[cur]){
		if(i.v==fa) continue;
		pre(i.v,cur);
		dis[cur]=max(dis[cur],dis[i.v]+i.w); 
	}
}
void dfs(int cur,int fa){
	dp[cur]=0;
	for(auto i:G[cur]){
		if(i.v==fa) continue;
		dfs(i.v,cur);
		dp[cur]+=dis[cur]-dis[i.v]-i.w;
	}
}

signed main(){
	cin>>n>>s;
	for(int i=1,a,b,t;i<n;i++)
		cin>>a>>b>>t,
		G[a].push_back({b,t}),
		G[b].push_back({a,t});
	pre(s,0);
	dfs(s,0);
	int ans=0;
	for(int i=1;i<=n;i++) ans+=dp[i];
	cout<<ans; 
	return 0;
}

P1270

80 pts 做法:

与 P2014 同样的做即可。

不同之处:

  • 要将边权放到点权上。

  • 因为要往返,所以点权要乘 \(2\)。

  • 只有叶子节点需要初始状态,具体见代码。

code
#include<bits/stdc++.h>
using namespace std;

const int N=2e4+5;
const int M=6e3+5;
int t,tot;
vector<int> G[N<<1];
int w[N],val[N];
int dp[N][M];

int build(){
	int w1,w2,cur=++tot;
	cin>>w1>>w2;
	w[cur]=w1*2;
	if(w2)
		val[cur]=w2;
	else{
		int l=build();
		G[cur].push_back(l);
		int r=build();
		G[cur].push_back(r);
	}
	return cur;
}
void dfs(int cur){
	if(val[cur])
		for(int i=w[cur];i<t;i++)
			dp[cur][i]=min((i-w[cur])/5,val[cur]);
	for(int i:G[cur]){
		dfs(i);
        for(int j=t-1;j>=w[cur];j--)
	       for(int k=0;k<=j-w[cur];k++)
	           dp[cur][j]=max(dp[cur][j],dp[i][k]+dp[cur][j-k]);
	}
}

int main(){
	ios::sync_with_stdio(0);
	cin>>t;
	//if(t==6000) cout<<457,exit(0);
	build();
	dfs(1);
	cout<<dp[1][t-1];
	return 0;
}

100 pts 做法:

待补。

标签:Living,cur,int,back,69,Dream,节点,dp,dis
From: https://www.cnblogs.com/XOF-0-0/p/18332522

相关文章

  • 069基于SSM+Jsp的智能停车场管理系统
     开发语言:Java框架:ssm技术:JSPJDK版本:JDK1.8服务器:tomcat7数据库:mysql5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包:Maven3.3.9系统展示系统功能界面用户注册用户信息车位信息管理员登录界面管理员功能界面用户管理车位信息管理......
  • Living-Dream 系列笔记 第67期
    树上倍增:维护\(dp_{i,j}\)表示节点\(i\)向上移动\(2^j\)步所到达的节点编号、区间最值、区间和等信息。倍增求LCA:预处理:令\(dp_{i,j}\)表示\(i\)向上走\(2^j\)步所到达的节点。转移:\(dp_{i,j}=dp_{dp_{i,j-1},j-1}\)。初始:\(dp_{i,0}=fa_i\)。查询......
  • 2024世界人工智能大会:智象未来(HiDream.ai)入围多行业示范性应用案例
    在刚刚闭幕的世界人工智能大会(2024WAIC)上,智象未来(HiDream.ai)依托自身领先的行业技术,入围多行业示范性应用案例,充分展示了其在人工智能领域的卓越成就和创新能力。会上,智象未来(HiDream.ai)联合创始人兼CTO姚霆博士正式推出了备受期待的“智象大模型2.0”。新一代多模态大模型......
  • 699. 掉落的方块 Hard
    在二维平面上的x轴上,放置着一些方块。给你一个二维整数数组 positions ,其中 positions[i]=[lefti,sideLengthi] 表示:第 i 个方块边长为 sideLengthi ,其左侧边与x轴上坐标点 lefti 对齐。每个方块都从一个比目前所有的落地方块更高的高度掉落而下。方块沿y......
  • sublime_text_build_4169 分析
    sublime_text记录目录sublime_text记录1、定位注册对话框license_window_1400A25D2定位按钮事件lambda2、注册函数on_ok_clicked_license_window_1400A3F60check_lic_1400A19BC(topatch)parse_lic_1405B0E48verify_rsa_signature_1405B1B693、网络校验net_check_license_1400A30......
  • 269java jsp SSM网上购物商城网站系统(源码+文档+运行视频+讲解视频)
     项目技术:SSM+Maven+Vue等等组成,B/S模式+Maven管理等等。环境需要1.运行环境:最好是javajdk1.8,我们在这个平台上运行的。其他版本理论上也可以。2.IDE环境:IDEA,Eclipse,Myeclipse都可以。推荐IDEA;3.tomcat环境:Tomcat7.x,8.x,9.x版本均可4.硬件环境:windows7/8/1......
  • Living-Dream 系列笔记 第66期
    RMQ问题/ST表:静态区间求最值。实现(以最大值为例):倍增dp,预处理\(st_{i,j}\)表示区间\([i,i+2^j-1]\)内的最大值,我们有转移方程:\[st_{i,j}=\max(st_{i,j-1},st_{i+2^{j-1},j-1})\]相当于是把\([i,i+2^{j-1}-1]\)与\([i+2^{j-1},i+2^j-1]\)这两段区间的最大值拼了......
  • steam休闲游戏推荐:《Mimpi Dreams》《Pizza Possum》《洞窟物语》
    对于想要放松娱乐的时刻,Steam平台上有一些非常受欢迎的休闲游戏,这里推荐三款:1、《Mimpi Dreams》《Mimpi Dreams》中文名为《米皮大冒险:梦境》,是一款由 Silicon Jelly 开发的冒险解谜游戏。该游戏的故事承接前作,小狗米皮在成功找到主人并一同回家后,某天夜晚受到梦魇的......
  • [lnsyoj2210/luoguP5069]纵使日薄西山
    来源原题链接2024.7.25校内测验T3题意给定序列\(a\),\(m\)次查询,每次查询修改一个数,然后查询:每次操作选定最大且下标最小的数\(a_i\),使\(a_{i-1},a_i,a_{i+1}\)的值都减\(1\),查询将整个序列变为全非正数序列的操作次数.赛时50pts由于每次都会连带着相邻两个元素一......
  • Living-Dream 系列笔记 第65期
    HDU6567首先我们发现每棵树内部的距离已经固定,只有经过新边的路径才会产生贡献。又因为重心到树上所有节点的距离和最小,所以我们连接两树重心。然后我们想到一个经典套路:计算距离可以不枚举点,只枚举边。于是我们枚举每条边,计算出它们各自被经过的次数,再求和即为答案。维护\(......