K叉树的异或值和
题意:
给出n个节点,节点按照 (i−1)/2 为i的父亲进行建树。问这棵树每一个节点的size异或值的和是多少。
思路:
画完图发现这就是一个k叉树,对于k叉树有两个性质:
http://blog.youkuaiyun.com/jaihk662/article/details/77203877#reply
性质:对于一颗满k叉树而言,如果k是偶数,那么它的异或和就是树的大小
如果k是奇数,那么它的异或和就是任意一棵子树大小的异或和再异或树的大小
当k是奇数的时候可以直接去单独算出异或值,从根节点推到要算的层数。
然后就是找有多少不满足满k叉树的结构,其实也就是一个,那么就把这个当做一个结构继续查找直到最简单的结构时,判断有几个儿子奇数个就^1然后输出答案。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
int main()
{
//freopen("in.txt","r",stdin);
int t;
scanf("%d",&t);
while(t--) {
LL n,k;
scanf("%I64d%I64d",&n,&k);
if(k==1) {
if(n%4==0) printf("%I64d\n",n);
else if(n%4==1) printf("1\n");
else if(n%4==2) printf("%I64d\n",n+1);
else if(n%4==3) printf("0\n");
}
else {
LL ans = n;
while(1) {
if(n-1 <= k) {
if(n%2==0) ans ^= 1;
printf("%I64d\n",ans);
break;
}
LL num = 1,x = 1,b = 1;
while(0 <= num + x*k && num + x*k < n) {
x *= k;
num += x;
b ^= num;
}
LL l = (n-num-1)/x;
LL r = k-l-1;
if(k%2) {
if(l%2) ans ^= b;
if(r%2) ans ^= (b^num);
}
else {
if(l%2) ans ^= num;
if(r%2) ans ^= (num-x);
}
n -= (l*num+r*(num-x)+1);
ans ^= n;
}
}
}
return 0;
}