当前位置: 首页> 科技> 能源 > 大学生ppt自我介绍幻灯片_品牌形象策划_接广告的平台推荐_百度推广的价格表

大学生ppt自我介绍幻灯片_品牌形象策划_接广告的平台推荐_百度推广的价格表

时间:2025/8/29 1:40:08来源:https://blog.csdn.net/2301_80281705/article/details/147050506 浏览次数:0次
大学生ppt自我介绍幻灯片_品牌形象策划_接广告的平台推荐_百度推广的价格表

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节点这个叶子节点存入leafreturn ;}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;
}
关键字:大学生ppt自我介绍幻灯片_品牌形象策划_接广告的平台推荐_百度推广的价格表

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: