P11375 [GESP202412 六级] 树上游走

记录123

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const long long LIMIT=1e12;// 题目给出的上限,用来判断节点编号是否过大
int main(){//纯模拟 
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n;// 定义整型变量n,用来存储总的移动次数
	long long s;// 定义长整型变量s,存储初始节点编号(防溢出)
	string ops;// 定义字符串ops,用来存储长度为n的移动指令序列
	cin>>n>>s>>ops;
	int level=0;// 记录超出LIMIT范围的相对层数(可以理解为"虚层"),初始为0表示在安全范围内
	for(int i=0;i<n;i++){// 遍历整个指令字符串,对每一条指令进行实时决策
		char op=ops[i];// 取出当前第i步的移动指令字符
		if(op=='U'){// 如果当前指令是向上移动到父节点
			if(s==1) continue;// 如果已经在根节点(编号为1),无法继续向上,什么都不做
			if(level>0){// 如果之前在"虚层"(编号过大被隐藏了),向上走一步相当于减少一层虚层
				level--;
			}else{// 如果在真实编号的安全范围内,正常除以2找父节点
				s/=2;
			}
		}
		else if(op=='L'){// 如果当前指令是向左儿子移动 (编号 * 2)
			// 如果已经在虚层,或者下一步计算会超出限制,就只增加虚层层级,不实际计算编号
			if(level>0||s*2>LIMIT){
				level++;
			}else s*=2;// 在安全范围内,正常计算编号
		}
		else if(op=='R'){// 如果当前指令是向右儿子移动 (编号 * 2 + 1)
			// 同理,如果超出限制则只增加虚层层级
			if(level>0||s*2+1>LIMIT){
				level++;
			}else s=s*2+1;// 在安全范围内,正常计算编号
		}
	}
	cout<<s<<endl;// 循环结束后,level一定被减回0,此时的s就是最终答案,直接输出
	return 0;// 结束程序
}

前言

我是一名专注信奥赛(CSP-J/S、NOIP)的教练。

  • 如果你觉得这篇题解对你有帮助,欢迎点击关注我的CSDN账号,我会持续更新高质量算法解析。
  • 我深知算法思维的构建远比单纯通过题目更重要,本系列题解不局限于AC代码的堆砌,而是致力于拆解题目背后的逻辑链条与核心知识点
  • 备赛路上若遇瓶颈,欢迎随时评论或私信,我将甄选典型疑难问题,通过视频讲解或撰写专项文章的形式,为你提供深度答疑。

题目传送门https://www.luogu.com.cn/problem/P11375


💡 核心解题思路

这道题是经典的二叉树模拟与防溢出处理 问题。题目要求模拟在二叉树上的移动,但存在一个巨大的陷阱:虽然最终结果不超过 10121012 ,但在移动过程中,如果连续向左或向右走,节点编号会呈指数级增长,轻易突破 long long 的上限(约 9×10^18 ),导致溢出。

  1. 常规模拟

    • 向上移动(U):当前节点编号除以 2(s /= 2),根节点 1 除外。
    • 向左移动(L):当前节点编号乘 2(s *= 2)。
    • 向右移动(R):当前节点编号乘 2 加 1(s = s * 2 + 1)。
  2. 破局关键:引入"虚层"(level)机制

    为了防止在向下走时发生整数溢出,我们不能盲目计算。

    • 当向下走(LR)且计算结果超过上限 10121012 时,我们不进行实际的乘法运算 ,而是用一个变量 level 记录"出界"的层数(即 level++)。
    • 当向上走(U)时,如果 level > 0,说明我们还在界外,此时只需要 level-- 即可,无需做除法。
    • 只有当 level == 0 且当前节点在安全范围内时,才进行真实的 s /= 2 运算。
    • 题目保证最终结果在 10^12 以内,这意味着循环结束时,level 一定会被减回 0,此时的 s 就是最终答案。

🧩 代码分块详细解释

1. 头文件与常量定义
cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const long long LIMIT=1e12; // 定义安全边界常量,用于判断节点编号是否越界
  • 作用:引入标准库并定义题目给出的上限阈值 10121012 ,作为后续判断是否进入"虚层"的标准。
2. 输入与初始化
cpp 复制代码
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0); // 关闭输入输出同步,提升大数据量下的读取速度
    int n; // 记录总的移动次数
    long long s; // 记录当前真实的节点编号(必须用 long long 防溢出)
    string ops; // 存储长度为 n 的移动指令序列
    cin>>n>>s>>ops; // 读入移动次数、初始节点和指令字符串
    int level=0; // 核心变量:记录超出 LIMIT 范围的相对层数(虚层),0 表示在安全范围内
  • 作用 :完成基础数据的读取,并初始化"虚层"计数器 level
3. 核心模拟循环:向上移动 (U)
cpp 复制代码
    for(int i=0;i<n;i++){ // 遍历整个指令字符串,对每一条指令进行实时决策
        char op=ops[i]; // 取出当前第 i 步的移动指令字符
        if(op=='U'){ // 如果当前指令是向上移动到父节点
            if(s==1) continue; // 特判:如果已经在根节点(编号为1),无法继续向上,直接跳过
            if(level>0){ // 如果当前处于"虚层"(编号过大被隐藏了),向上走一步相当于减少一层虚层
                level--;
            }else{ // 如果在真实编号的安全范围内,正常执行除以 2 找父节点
                s/=2;
            }
        }
  • 作用:处理向上移动逻辑。优先消耗虚层深度,虚层耗尽后才执行真实的除法操作。
4. 核心模拟循环:向左/右移动 (L / R)
cpp 复制代码
        else if(op=='L'){ // 如果当前指令是向左儿子移动 (理论编号 * 2)
            // 如果已经在虚层,或者下一步计算会超出限制,就只增加虚层层级,不实际计算编号
            if(level>0||s*2>LIMIT){
                level++;
            }else s*=2; // 在安全范围内,正常计算编号
        }
        else if(op=='R'){ // 如果当前指令是向右儿子移动 (理论编号 * 2 + 1)
            // 同理,如果超出限制则只增加虚层层级
            if(level>0||s*2+1>LIMIT){
                level++;
            }else s=s*2+1; // 在安全范围内,正常计算编号
        }
    }
  • 作用 :处理向下移动逻辑。通过预判 s*2s*2+1 是否越界,决定是真实计算还是仅仅记录虚层。
5. 输出与结束
cpp 复制代码
    cout<<s<<endl; // 循环结束后,level 一定被减回 0,此时的 s 就是最终答案,直接输出
    return 0; // 结束程序
}
  • 作用 :输出最终停留在的安全节点编号。由于题目保证最终结果不越界,循环结束时 level 必然归零。

📊 核心逻辑总结表

代码模块 核心变量/操作 精炼作用 解决的痛点
边界定义 LIMIT = 1e12 设定安全阈值 为判断是否溢出提供量化标准
状态记录 level 记录虚层深度 避免在树极深处进行大数运算导致溢出
向上移动 level-- / s/=2 优先回退虚层 确保从极深节点返回时不会发生除零或错误计算
向下移动 level++ / s*=2 预判越界并标记 拦截即将溢出的乘法操作,将其转化为安全的层级记录
根节点特判 if(s==1) continue 防止无效操作 避免在根节点执行 U 操作时产生逻辑错误
相关推荐
川冰ICE1 小时前
JavaScript进阶③|Map_Set_WeakMap_WeakSet,新型数据结构
开发语言·javascript·数据结构
小雨下雨的雨1 小时前
鸿蒙PC用Electron框架 实现 房产交易系统核心算法深度解析
前端·javascript·算法·华为·electron·鸿蒙系统
CQU_JIAKE1 小时前
6.3[a]
算法
此生决int1 小时前
算法从入门到精通——字符串
数据结构·c++·算法·蓝桥杯
bIo7lyA8v1 小时前
算法复杂度下限证明与优化空间分析的技术8
算法
basketball6161 小时前
设计模式入门:7. 策略模式详解 C++实现
c++·设计模式·策略模式
luj_17681 小时前
硝酸体系核关联假说解析
服务器·c语言·开发语言·经验分享·算法
love_muming1 小时前
数据结构入门:栈与队列详解
java·开发语言·数据结构
Je1lyfish1 小时前
CMU15-445 (2025 Fall/2026 Spring) Project#4 - Concurrency Control
开发语言·数据库·c++·笔记·后端·算法·系统架构