HDU 6121 Build a tree(完全K叉树)

http://acm.hdu.edu.cn/showproblem.php?pid=6121

题意:
给你一颗完全K叉树,求出每棵子树的节点个数的异或和。

思路:

首先需要了解一些关于完全K叉树或满K叉树的一些知识:

对于每棵子树,只有三种情况:

①是满K叉树  ②不是满K叉树  ③叶子节点

并且非满K叉树最多只有一个,所以只需要将它进行特殊处理,具体看代码吧,说不清楚。代码参考了http://blog.csdn.net/my_sunshine26/article/details/77200282

当K=1时,树是链状的,需要打表找规律!

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<sstream>
 6 #include<vector>
 7 #include<stack>
 8 #include<queue>
 9 #include<cmath>
10 #include<map>
11 #include<set>
12 using namespace std;
13 typedef long long ll;
14 typedef pair<int,ll> pll;
15 const int INF = 0x3f3f3f3f;
16 const int maxn=100+5;
17
18 ll n, k, ans;
19 ll num[maxn];
20 int depth;
21
22 void init()
23 {
24     num[0]=0;
25     for(int i=1;i<=depth;i++)
26     {
27         num[i]=num[i-1]+pow((long double)k,(long double)i-1);  //因为pow默认是pow(int,int),没有对应long long的,所以我这儿用long double来代替了一下
28     }                                                          //当然这里可以自己用快速幂来计算
29 }
30
31 int main()
32 {
33     //freopen("in.txt","r",stdin);
34     int T;
35     scanf("%d",&T);
36     while(T--)
37     {
38         scanf("%I64d%I64d",&n,&k);
39         if(k==1)                  //特判
40         {
41             ll tmp=n%4;
42             if(tmp==0) ans=n;
43             else if(tmp==1) ans=1;
44             else if(tmp==2) ans=n+1;
45             else ans=0;
46             printf("%I64d\n",ans);
47             continue;
48         }
49
50         depth=1;
51         ll tmp=n-1;
52         //计算树的深度
53         while(tmp>0)
54         {
55             tmp=(tmp-1)/k;
56             depth++;
57         }
58         init(); //预处理前i层的节点个数
59         ans=0;
60         ans^=(n-num[depth-1])&1; //先处理一下最后一层
61         depth--;
62         ll now=2;  //当前从下往上第几层
63         ll pos=(n-1-1)/k;
64         while(depth>0)
65         {
66             ll left=num[depth-1];  //当前层数最左边编号
67             ll right=num[depth]-1; //当前层数最右边编号
68             ll tmp1=num[now];      //左边树大小
69             ll tmp2=num[now-1];    //右边树大小
70
71             //奇数才有贡献
72             if((pos-left)&1)   ans^=tmp1;
73             if((right-pos)&1)  ans^=tmp2;
74
75             ll cnt=pos;
76             while(cnt<=(n-1-1)/k)  cnt=cnt*k+1;
77             ans^=(num[now-1]+n-cnt);  //单独处理临界点子树
78             now++;
79             depth--;
80             pos=(pos-1)/k;
81
82         }
83         printf("%I64d\n",ans);
84     }
85     return 0;
86 }
时间: 2024-11-02 23:30:41

HDU 6121 Build a tree(完全K叉树)的相关文章

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 n−1

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

hdu6121 Build a tree 模拟

/** 题目:hdu6121 Build a tree 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6121 题意:n个点标号为0~n-1:节点i的父节点为floor((i-1)/k); 0是根节点. 求这个树的所有节点为根的子树的节点数的异或和. 思路:模拟 可以发现k = min(k,n-1):即:k>=n-1时候结果一样. 然后画图可以发现是一个满k叉树(叶子不一定满). 然后发现:如果这是一个叶子也满的k叉树,那么直接就可以计算出结果. 当不

HDU 4417 (划分树+区间小于k统计)

题目链接:  http://acm.hdu.edu.cn/showproblem.php?pid=4417 题目大意:给定一个区间,以及一个k值,求该区间内小于等于k值的数的个数.注意区间是从0开始的. 解题思路: 首先这题线段树可以解.方法是维护一个区间最大值max,一个区间点个数s,如果k>max,则ans=s+Q(rson),否则ans=Q(lson). 然后也可以用求区间第K大的划分树来解决,在对原来求第K大的基础上改改就行,方法如下: Build方法同第K大. 对于Query: ①左区

hdu 5378 Leader in Tree Land(dp+逆元)

题目链接:hdu 5378 Leader in Tree Land 问题可以理解成N个节点的树,有K个ministers的概率,最后乘上N!.每个节点为ministers的概率即为1 / son(以该节点为根节点的子树包含的节点个数),同样不为ministers的概率为(son-1)/son.所以没有必要考虑树的结构,直接根句子节点的个数转移dp[i][j] dp[i][j] = dp[i-1][j-1] * 1 / son[u] dp[i][j] = dp[i-1][j] * (son[u]-

HDU 4896 Minimal Spanning Tree(矩阵快速幂)

题意: 给你一幅这样子生成的图,求最小生成树的边权和. 思路:对于i >= 6的点连回去的5条边,打表知907^53 mod 2333333 = 1,所以x的循环节长度为54,所以9个点为一个循环,接下来的9个点连回去的边都是一样的.预处理出5个点的所有连通状态,总共只有52种,然后对于新增加一个点和前面点的连边状态可以处理出所有状态的转移.然后转移矩阵可以处理出来了,快速幂一下就可以了,对于普通的矩阵乘法是sigma( a(i, k) * b(k, j) ) (1<=k<=N), 现在

Bestcoder round #65 &amp;&amp; hdu 5593 ZYB&#39;s Tree 树形dp

Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 354    Accepted Submission(s): 100 Problem Description ZYB has a tree with N nodes,now he wants you to solve the numbers of nodes distanced no m

HDU 4107 Gangster Segment Tree线段树

这道题也有点新意,就是需要记录最小值段和最大值段,然后成段更新这个段,而不用没点去更新,达到提高速度的目的. 本题过的人很少,因为大部分都超时了,我严格按照线段树的方法去写,一开始居然也超时. 然后修补了两个地方就过了,具体修改的地方请参看程序. 知道最大值段和最小值段,然后修补一下就能过了.不是特别难的题目. #include <stdio.h> #include <string> #include <algorithm> using namespace std; c

hdu 2489 Minimal Ratio Tree 枚举+最小生成树

点的总数很小,直接枚举就好. #include <stdio.h> #include <string.h> #define N 20 #define inf 1000000 int mk[N],n,k,ans[N]; double low[N],val[N]; double map[N][N],MIN; double prim() { int i,j; double sum=0; double tot=0; for(i=1;i<=n;i++) low[i]=inf; int