ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

P8046 [COCI2015-2016#4] CHEWBACCA 题解

2022-08-18 15:01:22  阅读:126  来源: 互联网

标签:return int 题解 COCI2015 编号 CHEWBACCA 节点 LL


发现自己的思路与那篇题解不同,而且可以跑更大的数据,所以来写个题解。

题意:给定一棵满 \(k\) 叉树,树的节点同层从左往右编号,深度较小的节点的编号一定小于深度较大的节点的编号,多次询问两点距离。

先思考 \(k=2\) 的情况。

我们知道,一个节点的左儿子就是它的编号乘二,右儿子的编号就是它的编号乘二加一,父亲的编号是它的编号除二向下取整。这个除二向下取整是个好性质,保证了倍增向上跳时能快速找到 \(2^m\) 级祖先。

现在看 \(k=3\) 的情况。

\(2\) 的儿子是 \(5,6,7\),而我们希望这是 \(6,7,8\)。

如何推广 \(k=2\) 呢?注意到 \(i\) 层的节点刚好是 \(2\) 进制下有 \(i\) 位的所有数从大到小的排列,首先我们需要前 \(i\) 层共 \(k^i-1\) 个节点。

考虑一个这样第 \(i\) 层有 \((k-1) \cdot k^{i-1}\) 个节点的图

这个图相当于把原树复制了 \(k-2\) 遍并重新编号。

前 \(i\) 层共 \(k^i-1\) 个节点,满足我们推广的需要。

这样 \(i\) 层刚好从 \((10\cdots0)_k\)(\(i\) 个 \(0\)) 开始编号,最后一位的 \(k\) 个数刚好对应同一个父亲,我们要的编号除以 \(k\) 是父亲性质也满足了。

怎么找到一个节点的新编号呢?先找到它在第几层,然后把它的编号加上那 \(k-2\) 棵树前 \(i-1\) 层节点个数之和即可。

这样的好处是我们可以倍增跳节点了,可以把数据限制从 \(n\) 改为 \(d\),\(d\) 为深度。

不过既然深度是 \(\log\) 级别的,估计改到那时就要 \(k\) 进制输入了吧 /xyx

反正树不高,我的实现仍是暴力向上跳。

#include <cstdio>
#include <iostream>
#include <algorithm>
#define LL long long
using namespace std;
const int M = 50;
LL n, k; int q; LL sum1[M], sum2[M], sum[M], step[M], num[M];
int getdep(LL x){ // 原编号算深度
    for(int i = 1; i <= 30; i++) {
		if(sum[i-1] >= x) return i;
	}
    return 0;
}
int dep(LL x){ // 新编号算深度
	for(int i = 1; i <= 30; i++){
		if(sum2[i] >= x) return i;
	} return 0;
}
LL solve(LL x, LL y){
    if(k == 1) return max(x, y) - min(x, y);
    int depx = getdep(x), depy = getdep(y), ans = 0;
    if(x != 1) x += (k-2) * sum[depx - 2];
    if(y != 1) y += (k-2) * sum[depy - 2];
    // 此时得到新的 x 与 y,后面看另一篇题解就够了
    while(x != y){
    	if(x < y) swap(x, y);
    	x /= k; ++ans;
	}
	return ans;
}
int main(){
    scanf("%lld %lld %d", &n, &k, &q);
    sum[0] = num[0] = 1ll; step[0] = k;
    for(int i = 1; i <= 30; i++)
        num[i] = num[i-1] * 2, step[i] = step[i-1] * k, sum[i] = sum[i-1] + step[i-1];
    sum2[1] = k-1;
    for(int i = 1; i <= 30; i++)
    	sum2[i] = sum2[i-1] * k;
    while(q--){
        LL x, y;
        scanf("%lld %lld", &x, &y);
        printf("%lld\n", solve(x, y));
    }
}

标签:return,int,题解,COCI2015,编号,CHEWBACCA,节点,LL
来源: https://www.cnblogs.com/purplevine/p/16598706.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有