hdu--6121--Build a tree
来源:互联网 发布:js bind 原理 编辑:程序博客网 时间:2024/06/05 02:08
Build a tree
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)Total Submission(s): 535 Accepted Submission(s): 167
Problem Description
HazelFan wants to build a rooted tree. The tree has n nodes labeled 0 to n−1 , and the father of the node labeled i is the node labeled ⌊i−1k⌋ . 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(1≤T≤5) , denoting the number of test cases.
For each test case:
A single line contains two positive integersn,k(1≤n,k≤1018) .
For each test case:
A single line contains two positive integers
Output
For each test case:
A single line contains a nonnegative integer, denoting the answer.
A single line contains a nonnegative integer, denoting the answer.
Sample Input
25 25 3
Sample Output
76
题目给出节点数为n的满k叉树,求出这棵满k叉树所有子树节点个数的异或总和。
解题思路:
对于所有的子树,可能会存在一棵不是满k叉树,就是编号为n-1的节点所在的那棵树,就把这棵子树的根节点作为
分界点,由满k叉树的性质知道,这个分界点的左边为满k叉树,而这个点的右边是比左边少一层的满k叉树。由此
可以得出一个结论,在每一层有三种情况,满二叉树,不满的二叉树,以及少一层的满k叉树。从叶子节点开始向上递归处理,把这三种情况分开处理。满的k叉树的节点个数比较容易得出,对于那个不满的,可以用右边的那种情况,加上多出来的节点数。需要注意的是k为1的情况要进行特殊处理。
更多细节性的东西,代码中有注释:
C++ Code
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include <bits/stdc++.h>
#define ll long long
#define maxn 105
using namespace std;
ll n, k;
ll num[maxn];
ll power(ll a, ll n)
{
///快速幂
ll ans = 1;
while(n)
{
if(n & 1)
ans *= a;
a *= a;
n >>= 1;
}
return ans;
}
void init(ll k, ll depth)
{
///预处理出完全k叉树前i层节点个数和
for(int i = 1; i <= depth; i++)
num[i] = (power(k, i) - 1) / (k - 1); ///k^0+k^1+k^2....k^i,(每一层为k^i);
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
ll ans;
scanf("%lld%lld", &n, &k);
if(k == 1) ///变为为链表
{
ll temp = n % 4;
if(temp == 0)
ans = n;
else if(temp == 1)
ans = 1;
else if(temp == 2)
ans = n + 1;
else
ans = 0;
printf("%I64d\n", ans);
continue;
}
int depth = 1; ///求出树的高度
ll res = n - 1;
while(res > 0)
{
res = (res - 1) / k; ///求父节点,
depth++; ///高度加一
}
init(k, depth);
ans = n; ///根节点为0的子树
if((n - num[depth - 1]) & 1) ///异或可以相互抵消
ans ^= 1;
depth--;
ll pos = (n - 1 - 1) / k; ///临界点在以编号为pos节点为根的子树上
int now = 2; ///当前是从下往上第几层
while(depth > 1) ///depth等于1,即变为以0为根节点的子树时,结束递归
{
ll left = num[depth - 1]; ///当前层最左边节点的编号
ll right = num[depth] - 1; ///当前层最右边节点的编号
ll temp1 = num[now]; ///当前层满k叉树 子树节点个数
ll temp2 = num[now - 1]; ///当前层满k叉树 层数减1后 子树节点个数
if((pos - left) & 1) ///临界点左边满k叉树的个数为奇数,那么结果异或上节点个数,否则异或相互抵消,不计
ans ^= temp1;
if((right - pos) & 1) ///同理
ans ^= temp2;
ll cnt = pos;
while(cnt <= (n - 1 - 1) / k) ///由于cnt*k+1<=n-1,左边会爆long long,故转化为除法。
cnt = cnt * k + 1; ///求出这个不满k叉树最左边的子叶编号,则n-cnt就是这个不满k叉树的子叶个数,拿右边少一层的满k叉树节点个数加上n-cnt就是这个不满k叉树的节点数
ans ^= num[now - 1] + n - cnt; ///临界点的子树特殊处理
now++;
depth--;
pos = (pos - 1) / k; ///界限向上推一个
}
printf("%I64d\n", ans);
}
return 0;
}
#define ll long long
#define maxn 105
using namespace std;
ll n, k;
ll num[maxn];
ll power(ll a, ll n)
{
///快速幂
ll ans = 1;
while(n)
{
if(n & 1)
ans *= a;
a *= a;
n >>= 1;
}
return ans;
}
void init(ll k, ll depth)
{
///预处理出完全k叉树前i层节点个数和
for(int i = 1; i <= depth; i++)
num[i] = (power(k, i) - 1) / (k - 1); ///k^0+k^1+k^2....k^i,(每一层为k^i);
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
ll ans;
scanf("%lld%lld", &n, &k);
if(k == 1) ///变为为链表
{
ll temp = n % 4;
if(temp == 0)
ans = n;
else if(temp == 1)
ans = 1;
else if(temp == 2)
ans = n + 1;
else
ans = 0;
printf("%I64d\n", ans);
continue;
}
int depth = 1; ///求出树的高度
ll res = n - 1;
while(res > 0)
{
res = (res - 1) / k; ///求父节点,
depth++; ///高度加一
}
init(k, depth);
ans = n; ///根节点为0的子树
if((n - num[depth - 1]) & 1) ///异或可以相互抵消
ans ^= 1;
depth--;
ll pos = (n - 1 - 1) / k; ///临界点在以编号为pos节点为根的子树上
int now = 2; ///当前是从下往上第几层
while(depth > 1) ///depth等于1,即变为以0为根节点的子树时,结束递归
{
ll left = num[depth - 1]; ///当前层最左边节点的编号
ll right = num[depth] - 1; ///当前层最右边节点的编号
ll temp1 = num[now]; ///当前层满k叉树 子树节点个数
ll temp2 = num[now - 1]; ///当前层满k叉树 层数减1后 子树节点个数
if((pos - left) & 1) ///临界点左边满k叉树的个数为奇数,那么结果异或上节点个数,否则异或相互抵消,不计
ans ^= temp1;
if((right - pos) & 1) ///同理
ans ^= temp2;
ll cnt = pos;
while(cnt <= (n - 1 - 1) / k) ///由于cnt*k+1<=n-1,左边会爆long long,故转化为除法。
cnt = cnt * k + 1; ///求出这个不满k叉树最左边的子叶编号,则n-cnt就是这个不满k叉树的子叶个数,拿右边少一层的满k叉树节点个数加上n-cnt就是这个不满k叉树的节点数
ans ^= num[now - 1] + n - cnt; ///临界点的子树特殊处理
now++;
depth--;
pos = (pos - 1) / k; ///界限向上推一个
}
printf("%I64d\n", ans);
}
return 0;
}
阅读全文
0 0
- HDU 6121 Build a tree
- hdu 6121 Build a tree
- hdu 6121 Build a tree
- HDU 6121Build a tree
- hdu--6121--Build a tree
- hdu--6121:Build a tree
- hdu 6121 Build a tree
- HDU-6121 Build a tree
- hdu 6121 Build a tree
- HDU 6121 Build a tree【】
- HDU 6121 Build a tree [想法题]
- HDU 6121 Build a tree [想法题]
- hdu 6121 Build a tree (模拟)
- HDU 6121 Build a tree (技巧)
- hdu 6121 Build a tree (图论)
- HDU 6121 Build a tree(递归)
- hdu 6121(Build a tree) 瞎搞+麻烦
- HDU 6121 Build a tree(找规律+implement)
- TSUNG学习教程 安装与使用(二)
- UML类图知识简介
- mysql和oracle的区别(功能性能、选择、使用它们时的sql等对比)
- D
- Lucas定理(板子+理解
- hdu--6121--Build a tree
- Ubuntu的php支持curl
- 使用storm统计英文版<<圣经>>的词频
- LintCode 在O(1)时间复杂度删除链表节点
- Spring中classpath*和classpath的区别
- HDU 2883 kebab(离散化+最大流)
- nyoj 37回文字符串
- linux下启动Oracle服务和监听程序
- Linux功耗管理(6)_Generic PM之Suspend功能