HDU 6121 Build a tree —— 2017 Multi-University Training 7

HazelFan wants to build a rooted tree. The tree has nn nodes labeled 0 to n−1, and the father of the node labeled i is the node labeled 

 

. HazelFan wonders the size of every subtree, and you just need to tell him the XOR value of these answers.

Input

The first line contains a positive integer T(1T5)T(1≤T≤5), denoting the number of test cases. 
For each test case: 
A single line contains two positive integers n,k(1n,k1018)n,k(1≤n,k≤1018). 
Output

For each test case: 
A single line contains a nonnegative integer, denoting the answer.Sample Input

2
5 2
5 3

Sample Output

7
6

题意:画一下题目介绍的树,发现这是一个k叉树,那么题目要求所有子树大小的异或和。
思路:我们从序号为n的节点开始,往上求异或和。n计算到某一层时,对于处在n节点左边的节点(子树),它们是t+1层的满k叉树,在右边的节点(子树)是t层的满二叉树,
满二叉树的大小可以通过打表得到。根据异或计算的性质,大小相同的子树进行异或,有奇数个进行异或时结果为该子树的大小,偶数个时为0。
而对n位置节点的子树来说,不是满二叉树就是非满二叉树,而且在计算这个子树大小时一旦它在某一层是非满二叉树,接下来往上它就一直是非满二叉树。
还有,k==1时特判一下。
具体实现参看代码。

AC代码:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long LL;
LL n, k;
LL num[100];
int main()
{
    int T;
    cin>>T;
    num[0]=1;
    while(T--)
    {
        scanf("%lld %lld", &n, &k);
        if(k==1){
            if(n==1)
                printf("%d\n", 1);
            else if(n==2)
                printf("%d\n",3);
            else if(n==3)
                printf("%d\n", 0);
            else 
            {
                int k=n%4;
                if(k==0)
                    printf("%lld\n", n);
                else if(k==1)
                    printf("%d\n", 1);
                else if(k==2)
                    printf("%lld\n", n+1);
                else
                    printf("%d\n", 0);
            }
            continue;
        }
        n--;
        int level=0,t=0;
        LL lm=0, rm=0;
        while(rm<n){
            t++;
            lm=rm+1;
            rm=lm*k;
            num[t]=rm+1;
        }
        LL res=0,left,right,s=n+1,m;
        t=0; 
        bool flag=0;
            LL mid=n%k;//mid判断是否为满k叉树, m为非满k叉树的大小 
            left=n-mid-lm+1;
            //cout<<left<<endl;
            if(left&1){
                res^=num[0];
            }
            if(mid&1)
                res^=num[0];
            if(mid)
                flag=1;
                
            m=(n-(n-1)/k*k)*num[0]+1;
            //cout<<m<<endl;
            while(n)
            {
                
                //cout<<res<<'*'<<endl;
                
                t++;
                //cout<<t<<' '<<m<<endl;
                
                n=(n-1)/k;
                if(n<=0)
                    break;
                
                mid=n%k; 
                lm=(lm-1)/k;
                rm=(rm-1)/k;
                //cout<<lm<<' '<<n<<' '<<rm<<endl;
                right=rm-n;
                left=n-lm+1;
                if(flag||mid){
                    flag=1;
                    left--;
                    res^=m;
                }
                
                if(left&1)
                    res^=num[t];
                if(right&1)
                    res^=num[t-1];
                m+=(n-(n-1)/k*k-1)*num[t]+(((n-1)/k+1)*k-n)*num[t-1]+1;
                
            }
        res^=s;
        printf("%lld\n", res);
    }
    return 0;
}

 



posted @ 2017-08-22 19:07  Bangbangbanana  阅读(130)  评论(0编辑  收藏  举报