当前位置: 首页 > news >正文

G-升!龙!_牛客周赛 Round 88

G-升!龙!_牛客周赛 Round 88

树上 d p dp dp,树上前缀和,树的链剖

题目大意:

给一颗有 n n n 节点的树,每个节点的权值为 a i a_i ai

定义:从根节点 1 1 1 到 叶子节点的 简单路径权值之和为 该路径的美丽值

树的价值为 路径美丽值的最大值。

给定 q q q 次操作,每次操作将 x x x 节点断开,接到 y y y 节点上,每次操作计算处树的价值,操作后将树恢复原样

思路:

  • 首先,在不操作的时候先处理出 所有树的简单路径 的权值之和

可以用树上 前缀和 实现:

vector<int> pre[N];//从根节点1到每个节点的权值之和

dfs(1);
//从根节点开始,每次到一个点就用该点的父节点更新该点到根节点的权值之和
//从上往下dfs更新
void dfs(int u) {
    pre[u]=pre[fa[u]]+a[u];
    for(auto x:g[u]) {
        dfs(x);
    }
}
  • 那么在处理所有简单路径权值之和的时候,因为要求最大的简单路径之和,需要保留一下叶子节点的树上前缀和

将叶子节点存储到 l e a f leaf leaf 数组中,并记录它是第几个被遍历到的叶子节点,存入 d f n dfn dfn 数组中

vector<int> leaf,dfn(n+1);

dfs(1);

void dfs(int u) {
    if(g[u].size()==0) {
        //叶子节点
        dfn[u]=leaf.size()+1;//标记u节点为第leaf.size()+1出现的
        leaf.push_back(u);//将u节点这个叶子节点存入leaf
        return ;
    }
    for(auto x:g[u]){
        dfs(x);
    }
}
  • 记录完 l e a f leaf leaf 节点的路径之和后,就可以考虑在不操作的时候如何 ( O 1 ) (O1) (O1) 解决最大的路径查询

预处理处叶子节点 l e a f leaf leaf 的前缀最大值数组 p r e _ m x pre\_mx pre_mx

如果考虑操作,那么就应该考虑其中有部分连续区间要被带走,那么应该处理出叶子节点 l e a f leaf leaf 的前缀最大值数组 p r e _ m x pre\_mx pre_mx 和 后缀最大值数组 s u f _ m x suf\_mx suf_mx

vector<int> pre_mx(n+10,0),suf_mx(n+10,0);
//将leaf整体后移一位更好处理前缀和
for(int i=1;i<leaf.size();i++){
    pre_mx[i]=max(pre_mx[i-1],pre[leaf[i]]);
}
for(int i=leaf.size()-1;i>=1;i--){
    suf_mx[i]=max(suf_mx[i+1],pre[leaf[i]]);
}
  • 考虑将 x x x 节点断开,损失的叶子节点的区间,可以考虑记录每个点能到达的最左边叶子 L i L_i Li 和能到达的最右边叶子 R i R_i Ri 可以考虑递归处理
vector<int> L(n+1)R(n+1);
dfs(1);
//先dfs到叶子节点,再由下往上更新
void dfs(int u) {
    if(g[u].size()==0) {
        L[u]=g[u]=u;
        return ;
    }
    for(auto x:g[u]) {
        dfs(x);
    }
    //处理完叶子节点的L,R后,往上递归处理父节点的
    L[u]=L[g[u].front()];
    R[u]=R[g[u].back()];
}

x x x 断开时, L [ x ] L[x] L[x] 记录的即为断开区间的左端点, R [ x ] R[x] R[x] 记录的为右端点

d f n [ L [ x ] ] dfn[L[x]] dfn[L[x]] 即为该点在 l e a f leaf leaf 数组中的下标

那么可以求出具体哪一段被断掉了

ans=max(ans,pre_mx[dfn[L[x]]]-1)//前面区间的最大值
ans=max(ans,suf_mx[dfn[R[x]]]+1)//后面区间的最大值

断掉这个区间之后,如果 x x x 的父节点为叶节点,那么需要考虑 p r e [ f a [ x ] ] pre[fa[x]] pre[fa[x]] ,如果不是叶节点,那么这个值不优,所以和 a n s ans ans m a x max max 无影响

ans=max(ans,pre[fa[x]));
  • 最后,需要考虑将 x x x 接到 y y y 节点上产生的新最大路径

考虑这个新最大路径应该是 p r e [ y ] pre[y] pre[y] + 以 x x x x x x 的叶节点的最大值, x x x x x x 的叶节点的最大值 可以考虑树上 d p dp dp 维护。

vector<int> son_mx(n+1,0);
dfs(1);
//先递归到叶子节点,再由下往上更新
void dfs(int u){
    if(g[u].size()==0){
        son_mx[u]=a[u];
        return ;
    }
    for(auto x:g[u]){
        dfs(x);
        son_mx[u]=max(son_mx[u],son_mx[x]+a[u]);
    }
}

处理完新最大路径,那么这道题就结束了

ans=max(ans,pre[y]+son_mx[x]);

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define fi first
#define se second
#define PII pair<int,int>
#define lowbit(x) x&-x
#define ALL(x) x.begin(),x.end()

const int mod = 1e9 + 7;
const int N = 2e5 + 10;

int n,q;
vector<int> a(N),fa(N);
vector<int> g[N]; 
vector<int> pre(N),pre_mx(N),suf_mx(N);
vector<int> L(N),R(N),leaf(1,0),dfn(N);
vector<int> son_mx(N);

void dfs(int u) {
	
	pre[u]=pre[fa[u]]+a[u];
	
	if(g[u].size()==0){
		L[u]=R[u]=u;
		dfn[u]=leaf.size();
		leaf.push_back(u);
		son_mx[u]=a[u];
		return ;
	}
	
	for(auto x:g[u]){
		dfs(x);
		son_mx[u]=max(son_mx[u],son_mx[x]+a[u]);
	}
	
	L[u]=L[g[u].front()];
	R[u]=R[g[u].back()];
}

void solve() {
	int n,q;cin>>n>>q;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}	
	for(int i=2;i<=n;i++){
		cin>>fa[i];
		g[fa[i]].push_back(i); 
	}
	
	dfs(1);
	
	for(int i=1;i<leaf.size();i++){
		pre_mx[i]=max(pre_mx[i-1],pre[leaf[i]]);
	}
	for(int i=leaf.size()-1;i>=1;i--){
		suf_mx[i]=max(suf_mx[i+1],pre[leaf[i]]);
	}
	
	while(q--){
		int x,y;cin>>x>>y;
		int ans=max(pre_mx[dfn[L[x]]-1],suf_mx[dfn[R[x]]+1]);
		ans=max(ans,pre[fa[x]]);
		ans=max(ans,pre[y]+son_mx[x]);
		cout<<ans<<'\n';
	}
}

signed main() {
	std::ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int T = 1;
//	cin >> T;
	while (T--) {
		solve();
	}
	return 0;
}

相关文章:

  • 深入源码级别看spring bean创建过程
  • Go语言类型捕获及内存大小判断
  • JVM核心机制:类加载×字节码引擎×垃圾回收机制
  • 硬盘分区格式方案之 MBR(Master Boot Record)主引导记录详解 笔记250407
  • 七彩虹隐星G15笔记本信息
  • 优化 Django 数据库查询
  • 数据库——Mysql
  • Vue学习笔记 - 安装与环境搭建
  • AI浪潮下的IT职业转型:医药流通行业传统IT顾问的深度思考
  • Java面试黄金宝典40
  • 小甲鱼python【p3】
  • Vue.js 实现下载模板和导入模板、数据比对功能核心实现。
  • Scala-面向对象2和集合
  • 解决 Kubernetes 中容器 `CrashLoopBackOff` 问题的实战经验
  • SpringBoot底层-数据源自动配置类
  • 版本控制工具——SVN
  • Linux之Shell脚本--命令提示的写法
  • Axure PR 9 中继器 08 添加行
  • JSON格式
  • Linux的那些基础常用命令汇总
  • 国内网店平台有哪些/沈阳网络优化培训
  • 武汉做商城网站建设/网站优化包括对什么优化
  • wordpress发送邮件插件/seo网络营销招聘
  • 泉州网站设计公司/外贸建站公司
  • 动漫制作专业软件有哪些/seo和sem的区别与联系
  • 做网站用空间好还是服务器好/网站排名优化外包公司