Description
给定一棵无限层的满二叉树,如果 (x) 是根,那么左孩子是 (2x),右孩子是 (2x+1)。现在有三种操作:将 (x) 所在层的所有节点整体向右循环移动 (k) 个单位;将 (x) 所在层的所有节点及其子树整体向右循环移动 (k) 个单位;输出 (x) 到根的路径。
Solution
实际上,由于访问到的层数不会超过 (63),我们只需要暴力记录每一层被循环移动的次数即可。对于第一种操作修改当层即可;对于第二种操作修改其后的所有层即可。
对于询问,我们只需要反解出实际位置,就得到了路径上所有点的位置,再把位置换算回下标即可。本质上,我们只需要提供位置和下标之间的换算即可。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 63;
int offset[N],n,t1,t2,t3,t4;
int get_level(int p)
{
return log2(p);
}
int pos2id(int p)
{
int level=get_level(p);
p=(p+(1ll<<level)+offset[level])%(1ll<<level)+(1ll<<level);
return p;
}
int id2pos(int p)
{
int level=get_level(p);
p=(p+(1ll<<level)-offset[level])%(1ll<<level)+(1ll<<level);
return p;
}
signed main()
{
ios::sync_with_stdio(false);
cin>>n;
while(n--)
{
cin>>t1;
if(t1==1)
{
cin>>t2>>t3;t3=-t3;
int level=get_level(t2);
offset[level]+=t3;
offset[level]%=1ll<<level;
offset[level]+=1ll<<level;
offset[level]%=1ll<<level;
}
if(t1==2)
{
cin>>t2>>t3;t3=-t3;
int level=get_level(t2);
t3%=1ll<<level;
t3+=1ll<<level;
t3%=1ll<<level;
for(int i=level;i<N;i++)
{
offset[i]+=t3;
offset[i]%=1ll<<i;
offset[i]+=1ll<<i;
offset[i]%=1ll<<i;
t3*=2;
}
}
if(t1==3)
{
cin>>t2;
t2=id2pos(t2);
/*cout<<"offset: ";
for(int i=0;i<4;i++) cout<<offset[i]<<" ";
cout<<endl;*/
while(t2!=0)
{
cout<<pos2id(t2)<<" ";
t2>>=1;
}
cout<<endl;
}
}
}