zoukankan      html  css  js  c++  java
  • HDU 6121 Build a tree(找规律+模拟)

    Build a tree

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)
    Total Submission(s): 946    Accepted Submission(s): 369


    Problem Description
    HazelFan wants to build a rooted tree. The tree has n nodes labeled 0 to n1, and the father of the node labeled i is the node labeled i1k. 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), denoting the number of test cases.
    For each test case:
    A single line contains two positive integers n,k(1n,k1018).
     
    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
     
    Source
     
    /*
    * @Author: lyuc
    * @Date:   2017-08-15 14:04:25
    * @Last Modified by:   lyuc
    * @Last Modified time: 2017-08-16 22:11:31
    */
    
    /*
     题意:给你一个n个节点的k叉树,然后让你求每个子树节点个数的异或和
    
     思路:
         当k等于1的时候处理会超时的,但是有规律:
             n%4=0    结果为n
             n%4=1    结果为1
             n%4=2    结果为n+1
             n%4=3    结果为0
         当n<=k+1时:
             如果      n%2==1
            结果      n
            
    
            如果      n%2==0
            结果      n+1
        如果是个完全k叉树:
            如果     k%2==0
            结果     n 
    
            如果     k%2==1
            结果     每层异或一个
        剩余的情况中:
            root节点的子树中最多只有一个子树是不完全k叉树,这棵树单独处理,然后剩下的是满k叉树
        按照上面的办法求
    
    */
    
    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <queue>
    #include <set>
    #include <map>
    #include <string>
    #include <math.h>
    #include <stdlib.h>
    #include <time.h>
    
    #define LL long long
    #define INF 0x3f3f3f3f
    #define MAXN 105
    
    using namespace std;
    
    int t;
    LL n,k;
    LL res;
    LL num[MAXN];
    
    inline void init(){
        res=0;
    }
    
    int main(){ 
        // freopen("in.txt", "r", stdin);
        // freopen("out.txt", "w", stdout);
        scanf("%d",&t);
        while(t--){
            init();
            scanf("%lld%lld",&n,&k);
            if(n<=k+1){//如果是矩阵上三角
                if(n%2==1){
                    printf("%lld
    ",n);
                }else{
                    printf("%lld
    ",n+1);
                }
            }else{
                if(k==1){//k=1的时候需要特殊处理
                    switch(n%4){
                        case 0:
                            printf("%lld
    ",n);
                            break;
                        case 1:
                            puts("1");
                            break;
                        case 2:
                            printf("%lld
    ",n+1);
                            break;
                        case 3:
                            puts("0");
                            break;
                    }
                }else{
                    //判断是不是完全树
                    LL deepth=1;//树的深度(不包括最后一行,根节点深度为0)
                    LL cur=1;
                    bool flag=false;
                    num[1]=1;
                    while(num[deepth]<n){
                        deepth++;
                        cur*=k;
                        num[deepth]=num[deepth-1]+cur;//计算出根节点到每层的节点数
                        if(num[deepth]==n){
                            flag=true;
                            break;
                        }
                    }
                    if(flag==true){//如果是完全树
                        if(k%2==0){//偶数叉树,异或到最后只是一个根节点了
                            printf("%lld
    ",n);
                        }else{//奇数叉树,异或到最后每层剩一个节点
                            cur=1;
                            while(cur<n){
                                res^=cur;
                                cur*=k;
                            }
                            printf("%lld
    ",res);
                        }
                    }else{//如果不是完全树
                        // 整棵树
                        res = n;
                        
                        // 最底层单独做
                        res ^= (n - num[deepth-1]) & 1;
    
                        --deepth;
                        LL p = (n - 2) / k; // [(n - 1) - 1] / k,倒数第 2 层开始
                        LL lid, rid, lnum, rnum, lch;
                        for(LL d = 2; p > 0; p = (p - 1) / k, ++d, --deepth)
                        {
                            // 当前层最左边结点的标号
                            lid = num[deepth-1];
    
                            // 当前层最右边结点的标号
                            rid = num[deepth] - 1;
                            
                            // 左边的子树(满的)的大小
                            lnum = num[d];
    
                            // 右边的子树(少一层,但也是满的)的大小
                            rnum = num[d - 1];
    
                            if((p - lid) & 1)
                                res ^= lnum;
    
                            if((rid - p) & 1)
                                res ^= rnum;
    
                            lch = p; // p 为根的子数最左小角的后代结点
    
                            while(lch <=(n - 2) / k) // lch * k + 1 <= n - 1
                                lch = lch * k + 1;
    
                            res ^= num[d-1] + n - lch;
                        }
                        printf("%lld
    ",res);
                    }
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    一台服务器Nginx配置多个域名(一级域名或二级)
    Nginx启动和停止
    git删除本地及远程分支
    纯js实现复制内容到剪切板
    js 实现字符串转日期进行比较大小
    git 本地分支与远程分支 新建/删除/合并
    设置Git 记住密码
    炒鸡简单的javaScript的call和apply方法
    如何打war包
    Git 查看远程分支、本地分支、删除本地分支及远程分支
  • 原文地址:https://www.cnblogs.com/wuwangchuxin0924/p/7376290.html
Copyright © 2011-2022 走看看