Codeforces 792D Paths in a Complete Binary Tree【二进制思维】

D. Paths in a Complete Binary Tree
time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

T is a complete binary tree consisting of n vertices. It means that exactly one vertex is a root, and each vertex is either a leaf (and doesn't have children) or an inner node (and has exactly two children). All leaves of a complete binary tree have the same depth (distance from the root). So n is a number such that n + 1 is a power of 2.

In the picture you can see a complete binary tree with n = 15.

Vertices are numbered from 1 to n in a special recursive way: we recursively assign numbers to all vertices from the left subtree (if current vertex is not a leaf), then assign a number to the current vertex, and then recursively assign numbers to all vertices from the right subtree (if it exists). In the picture vertices are numbered exactly using this algorithm. It is clear that for each size of a complete binary tree exists exactly one way to give numbers to all vertices. This way of numbering is called symmetric.

You have to write a program that for given n answers q queries to the tree.

Each query consists of an integer number ui (1 ≤ ui ≤ n) and a string si, where ui is the number of vertex, and si represents the path starting from this vertex. String si doesn't contain any characters other than 'L', 'R' and 'U', which mean traverse to the left child, to the right child and to the parent, respectively. Characters from si have to be processed from left to right, considering that ui is the vertex where the path starts. If it's impossible to process a character (for example, to go to the left child of a leaf), then you have to skip it. The answer is the number of vertex where the path represented by si ends.

For example, if ui = 4 and si = «UURL», then the answer is 10.

Input

The first line contains two integer numbers n and q (1 ≤ n ≤ 1018, q ≥ 1). n is such that n + 1 is a power of 2.

The next 2q lines represent queries; each query consists of two consecutive lines. The first of these two lines contains ui (1 ≤ ui ≤ n), the second contains non-empty string si. si doesn't contain any characters other than 'L', 'R' and 'U'.

It is guaranteed that the sum of lengths of si (for each i such that 1 ≤ i ≤ q) doesn't exceed 105.

Output

Print q numbers, i-th number must be the answer to the i-th query.

Example
Input
15 2
4
UURL
8
LRLLLLLLLL
Output
10
5

题目大意:

给你一个具有N个点的完全二叉树,其中有Q个查询,每次查询先给出一个点,作为基础点u,然后对于其有一个字符串操作,每个位子上的操作表示:

L:向u的左儿子走。

R:向u的右儿子走。

U:走到父亲节点。

给出一个字符串,问从u点最终走到了哪个编号的节点上去。


思路:


1、问题肯定是考虑如何改变编号的,我们如果能够动态的改变一个点的编号,那么问题就很容易解决了。

观察到从8走向1,其递减的趋势是4 2 1.明显有二进制趋势。

同理在观察到从8走向15,其递增的趋势也是4 2 1.那么我们不妨在二进制上做一做文章。


2、首先我们将一个具有8个节点的完全二叉树的所有编号都写成二进制形式:


很容易观察到,对应三种操作:

①L:将二进制表示中的最右边的那个1右移一位 (不能移动出界).

②R:将二进制表示中的最右边的那个1的后边哪位上加个1(如果有1就不加了).

③U:将二进制表示中的最右边的那个1前移一位(不能移动出界).


3、注意二进制越界问题。


Ac代码:

#include<stdio.h>
#include<string.h>
#include<math.h>
using namespace std;
#define ll __int64
char a[1005000];
int num[10000];
ll n,m,cnt;
void Getnum(ll u)
{
    memset(num,0,sizeof(num));
    int tmp=0;
    while(u)
    {
        num[tmp++]=u%2;
        u/=2;
    }
}
void Getcnt()
{
    ll uuu=n/2+1;
    while(uuu)
    {
        uuu/=2;
        cnt++;
    }
}
ll poww(ll contz)
{
    ll ans=1;
    while(contz)
    {
        contz--;
        ans*=2;
    }
    return ans;
}
int main()
{
    while(~scanf("%I64d%I64d",&n,&m))
    {
        cnt=0;
        Getcnt();
        while(m--)
        {
            ll u;
            scanf("%I64d",&u);
            Getnum(u);
            scanf("%s",a);
            int len=strlen(a);
            for(int i=0;i<len;i++)
            {
                if(a[i]=='L')
                {
                    for(int i=0;i<cnt;i++)
                    {
                        if(num[i]==1)
                        {
                            if(i!=0)num[i]=0,num[i-1]=1;
                            break;
                        }
                    }
                }
                if(a[i]=='R')
                {
                    for(int i=0;i<cnt;i++)
                    {
                        if(num[i]==1)
                        {
                            if(i!=0) num[i-1]=1;
                            break;
                        }
                    }
                }
                if(a[i]=='U')
                {
                    for(int i=0;i<cnt;i++)
                    {
                        if(num[i]==1)
                        {
                            if(i!=cnt-1)num[i+1]=1,num[i]=0;
                            break;
                        }
                    }
                }
            }
            ll ans=0;
            for(int i=0;i<cnt;i++)
            {
                if(num[i]==1)
                ans+=poww(i);
            }
            printf("%I64d\n",ans);
        }
    }
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值