题意:给出一个二叉树,根节点是1,节点x的左孩子是2*x,右孩子是2*x+1。给出以下三个操作
1 X K :将x所在的那一层的所有数右移K位(循环移动)
2 X K :将x所在的那一层的所有数右移K位(循环移动),并且其每个节点的子树也跟着移动
3 X :输出X到根节点1的路径
题解:因为移动的是值,所以原位置标号是不变的。我们只需记录该层移动了多少位,通过取mod可直接去现在所求X在的原位置标号。然后通过性质可以求出原位置标号的父亲节点,然后逆着求现在这个位置是什么值即可。
#include <bits/stdc++.h>
using namespace std;
const double EPS = 1e-8;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int maxn = 60 + 10;
int Q;
long long T, X, K;
long long Num[maxn], shift[maxn];
int level(long long x)
{
int ans = 0;
while(x){
x /= 2;
ans++;
}
return ans;
}
int main()
{
for(int i = 1; i <= 60; i++) Num[i] = 1LL << (i - 1);
scanf("%d", &Q);
while(Q--){
scanf("%I64d", &T);
if(T == 1){
scanf("%I64d%I64d", &X, &K);
int dep = level(X);
shift[dep] += K;
}
else if(T == 2){
scanf("%I64d%I64d", &X, &K);
long long now = 1;
for(int dep = level(X); dep <= 60; dep++){
shift[dep] += K * now;
now *= 2;
}
}
else{
scanf("%I64d", &X);
for(int dep = level(X); dep >= 1; dep--){
printf("%I64d%c", X, dep == 1 ? '\n' : ' ');
if(dep == 1) break;
long long mov = (shift[dep] % Num[dep] + Num[dep]) % Num[dep];
long long now = ((X - Num[dep]) + mov) % Num[dep] + Num[dep];
X = now / 2;
mov = ((-shift[dep-1]) % Num[dep-1] + Num[dep-1]) % Num[dep-1];
now = ((X - Num[dep-1]) + mov) % Num[dep-1] + Num[dep-1];
X = now;
}
}
}
return 0;
}