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

河南萌新联赛2025第(五)场题解:I J(LCA)

题目分析

题目描述

n个定理,每个定理需要a[i]的复习时间,除根节点外,每个定理必须先复习其前置定理,查询时对于q个复习策略,每个策略,每个策略需要复习k个指定定理,找到每个策略的最小时间。

思路分析

复习k个定理的最小时间——>在树中选择k个指定节点,求包含这些节点的所有祖先的权值和(最小连通子树的权重和)

要复习定理x,必须复习根到x路径上的所有定理,所以我们可以通过LCA算法来求解问题,找到通往每个节点路径上的全部权值和,再将通往按照时间戳排序后相邻两个节点的lca节点路径上的权值和删去,即可得到所求最小连通树的所有权值和啦~ (本题有多种解法,思路各有千秋,这里小编提供的是只用lca即可解决问题的解法)

话不多说上代码(牛客AC+详细注释)

#include<iostream>
#include<vector>
#include<string>
#include<cstring>
#include<algorithm>
//#include<bits/stdc++.h>
using namespace std;
#define int long long
const int MAX_N=500000+7,MAX_M=500000+7;int n,m,s;
int d[MAX_N];
int f[MAX_N][21];//倍增数组
int g=1,st[MAX_N];
int sum[MAX_N];//从根节点到当前节点路径的权值和
int a[MAX_N];//记录权值int head[MAX_N],cnt=-1;
struct Edge{int to,next;
}e[MAX_N*2];void dfs(int u,int fa){f[u][0]=fa;d[u]=d[fa]+1;st[u]=g++;sum[u]=sum[fa]+a[u];
//    cout<<a[u]<<":"<<sum[u]<<endl;for(int i=1;(1<<i)<=d[u];i++){f[u][i]=f[f[u][i-1]][i-1];}for(int i=head[u];i!=-1;i=e[i].next){int v=e[i].to;if(v!=fa)dfs(v,u);}
}void add(int u,int v){e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt;
}int lca(int u,int v){if(d[u]<d[v]) swap(u,v);//用深度更大的向上跳跃,跳至于另一个在同一深度的位置,这里统一使用u去跳跃,所以将u变为深度更大的值for(int i=20;i>=0;i--){if(d[f[u][i]]>=d[v])u=f[u][i];}//跳至深度在同一位置if(u==v) return v;//特判,若u=v,则说明v节点在根节点到u节点的路径上,此时v就是v和u的公共祖先for(int i=20;i>=0;i--){if(f[u][i]!=f[v][i]){u=f[u][i];v=f[v][i];}//将深度相同的两个节点同时上跳 那么最后一次跳一定是其最小公共节点}return f[u][0];
}
signed main(){memset(head,-1,sizeof head);cin>>n;int u,v;for(int i=1;i<=n;i++){cin>>a[i];//输入权值}for(int i=1;i<n;i++){cin>>u>>v;add(u,v);add(v,u);//存图,无向图,所以存两遍}dfs(1,0);//进入dfs开始预处理数组(倍增数组 和 路径权值和数组),从1开始,1为根节点,父节点为0cin>>m;while(m--){cin>>s;vector<int> t;//定义一个数组,用于记录当前策略所需复习的知识点即所包含的节点int numb;for(int i=0;i<s;i++){cin>>numb;t.push_back(numb);}sort(t.begin(),t.end(),[&](int x,int y){return st[x]<st[y];});//按照时间戳排序,排序后的数组相邻两个节点在树上也是距离最近的//此时他们的LCA能够以最少得中间节点连接不同的子树分支int ans=0;for(int i=0;i<s;i++){ans+=sum[t[i]];//遍历节点,将根节点到每个节点的权值和全部相加,此时的结果并不是所求结果,因为此时的路径有重复,即两节点之间的公共祖先权值会重复相加}for(int i=0;i<s-1;i++){ans-=sum[lca(t[i],t[i+1])];//所以再次遍历,找到相邻两节点的公共祖先,减去其路径上的权值和}//此时的结果是去掉重复路径的结果 为争取值cout<<ans<<endl;}return 0;
}
http://www.sczhlp.com/news/12650/

相关文章:

  • Ruby 和 Tesseract OCR 实现验证码识别
  • Kotlin 和 Tesseract OCR 实现验证码识别
  • ReasonRank:从关键词匹配到逻辑推理,排序准确性大幅超越传统方法
  • 【ARM Cache 及 MMU 系列文章 6.2 -- ARMv8v9 如何读取 Cache 内部数据并对其进行解析?】
  • ARM - SME 指令
  • 细思极恐怖如斯
  • 牛客2025多校 R5
  • HTML第三次作业 - 详解
  • 高效神经组合优化求解器解决最小最大异构容量车辆路径问题
  • 低成本电阻网络兼容FPGA_DPHY的简要概括
  • 2025 暑假集训 Day10
  • 8gu-JVM
  • JWT 这点小秘密,你们肯定知道!
  • tarjan学习笔记
  • 用stm32f407zgt6说明stm系列芯片命名规则
  • Diffusion model
  • 11
  • 2025.8.15
  • nacos安装及配置
  • 做题随笔:P8981
  • Github新锐从2000 star 冲刺到爆款级工具!到底是怎么做到的,真心不错!!!
  • 小剧场(为了维护机房他人的“机房语录”知识产权利益,本博客更名为小剧场)
  • JNI:全局引用和本地引用 - tomato
  • Github 23000+ star 又一神级开源项目,秒杀市面上主流收费产品,最主要是 轻量化部署!!!
  • 正点原子ESP32S3+ES8388+ESP-SR实现离线语音唤醒
  • 没想到,这也许是Github低代码界天花板,从0到1一分钟搭建系统!这搭建速度没谁啦!!!
  • 8/15
  • JNI 创建jobject的方法 - tomato
  • JNI 访问Java数组 - tomato
  • 腾讯云对象存储原生js上传