子树的大小 思维

该篇文章介绍了如何使用C++编程解决一个关于树结构的问题,即给定树的总节点数n、树的叉数m和查询结点k,计算以k为根的子树中的节点总数。通过递归计算最左孩子和最右孩子的下标,实现近似log(mn)的时间复杂度求解。
摘要由CSDN通过智能技术生成

//对于结点i,本题如果能找到i的最左孩子和最右孩子的下标,便可以迎刃而解
//对于第i个结点,其前面有i-1个结点,每个结点各有m个孩子,再加上1号结点
//可得第i个结点的最左孩子下标为(i-1)*m+2
//同理可得第i个结点的最右孩子下标为i*m+1(前i个结点各有m个孩子,再加上1号结点)
//故对于子树根结点,只需逐层累加最右孩子-最左孩子即可
//只需要处理最后一层的特殊情况:
//1、最左孩子下标超出n,说明子树在最后一层没有结点,直接退出
//2、最右孩子下标超出n,说明子树在最后一层的结点是非满的,将最右孩子下标改为n,累加后退出
//有1e5组询问,对于每组询问,可在近似logm n的时间复杂度内得出结果,不会超时
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;//注意本题必须开long long,否则会挂掉绝大部分测试点

void solve()
{
    int n,m,k;
    ll cnt=1;//cnt记录以k为根的子树的结点总数,初始化为1(一个根结点)
    //n为总结点数,m为树的叉数,k为待查询结点编号
    scanf("%d%d%d",&n,&m,&k);
    ll lchild=k,rchild=k;//开始计算最左孩子和最右孩子
    while(1)
    {
        bool flag=0;
        lchild=(lchild-1)*m+2;
        rchild=rchild*m+1;
        //cout<<"lchild = "<<lchild<<", rchild = "<<rchild<<endl;
        if(lchild>n)break;//最左孩子超出n,本层为空,直接退出
        if(rchild>=n)//最右孩子超出n
        {
            flag=1;//最后一次累加
            rchild=n;//改为n
        }
        cnt+=rchild-lchild+1;//累加最左孩子与最右孩子之差
        if(flag)break;
    }
    printf("%lld\n",cnt);
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        solve();
    }
    return 0;
}

  • 7
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值