【题目来源】
https://www.luogu.com.cn/problem/P11375
【题目描述】
小杨有一棵包含无穷节点的二叉树(即每个节点都有左儿子节点和右儿子节点;除根节点外,每个节点都有父节点),其中根节点的编号为 1,对于节点 i,其左儿子的编号为 2×i,右儿子的编号为 2×i+1。
小杨会从节点 s 开始在二叉树上移动,每次移动为以下三种移动方式的任意一种:
第 1 种移动方式:如果当前节点存在父亲节点,向上移动到当前节点的父节点,否则不移动;
第 2 种移动方式:移动到当前节点的左儿子;
第 3 种移动方式:移动到当前节点的右儿子。
小杨想知道移动 n 次后自己所处的节点编号。数据保证最后所处的节点编号不超过 10^12。
【输入格式】
第一行包含两个正整数 n 和 s,代表移动次数和初始节点编号。
第二行包含一个长度为 n 且仅包含大写字母 U、L 和 R 的字符串,代表每次移动的方式,其中 U 代表第 1 种移动方式,L 代表第 2 种移动方式,R 代表第 3 种移动方式。
【输出格式】
输出一个正整数,代表最后所处的节点编号。
【输入样例】
3 2
URR
【输出样例】
7
【说明/提示】
小杨的移动路线为 2→1→3→7。
对于全部数据,保证有 1≤n≤10^6,1≤s≤10^12。
【算法分析】
● 由于题目陈述的二叉树为“每个节点都有左儿子节点和右儿子节点”,故其为满二叉树。基于样例的移动示意图如下所示:
● long long 的绝对值最大值约为 9.22×10¹⁸(即 2⁶³≈9.22e18)。因此,long long 的数量级明确落在 10¹⁸ 次方级别。
● 题目只说最后所处的节点编号不超过 10^12,没有说经过的节点编号不超过 10^12,甚至会超过 long long 的范围 10^18 而爆掉。不过据题意,即便经过的编号超过了 10^12,最终还是会返回编号不超过 10^12 的位置,因此当遇到的编号超过 10^12 时,可无视即不移动。
● 若整数大于 2×10^9,就选择使用 long long 型:https://blog.youkuaiyun.com/hnjzsyjyj/article/details/132240042
【算法代码】
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL imx=1e12;
LL n,id,cnt;
char ch;
int main() {
cin>>n>>id;
while(n--) {
cin>>ch;
if(ch=='U') {
if(cnt!=0) {
cnt--;
continue;
}
if(id!=1) id=id/2;
}
else if(ch=='L') {
if(id*2>imx) cnt++;
else id=id*2;
}
else {
if(id*2>imx) cnt++;
else id=id*2+1;
}
}
cout<<id<<endl;
return 0;
}
/*
in:
3 2
URR
out:
7
*/
【参考文献】
https://blog.youkuaiyun.com/weixin_66461496/article/details/145453051
https://www.luogu.com.cn/problem/solution/P11375
https://blog.youkuaiyun.com/hnjzsyjyj/article/details/147077708