哈理工OJ 1248 The kth great number(平衡树求第k大数)

本文介绍了一道经典的平衡树模板题目,通过实现插入、删除和查找操作来维护一个动态的有序数列,并求出第k大的数。使用了自平衡二叉搜索树的数据结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=1248

The kth great number
Time Limit: 1000 MS Memory Limit: 65536 K
Total Submit: 108(36 users) Total Accepted: 65(35 users) Rating: Special Judge: No
Description
Xiao Ming and Xiao Bao are playing a simple Numbers game. In a round Xiao Ming can choose to write down a number, or ask Xiao Bao what the kth great number is. Because the number written by Xiao Ming is too much, Xiao Bao is feeling giddy. Now, try to help Xiao Bao.
Input
There are several test cases. For each test case, the first line of input contains two positive integer n, k. Then n lines follow. If Xiao Ming choose to write down a number, there will be an ” I” followed by a number that Xiao Ming will write down. If Xiao Ming choose to ask Xiao Bao, there will be a “Q”, then you need to output the kth great number.
Output
The output consists of one integer representing the largest number of islands that all lie on one line.
Sample Input
8 3
I 1
I 2
I 3
Q
I 5
Q
I 4
Q
Sample Output
1
2
3
Source
The 36th ACM/ICPC Asia Regional Dalian Site —— Online Contest

【中文题意】求第k大数是多少。
【思路分析】平衡树模板题,就是写的有点麻烦。
【AC代码】

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 1000005

typedef struct sbtnod
{
    int key,left,right,size;
}sbtnode;
int sbttail,sbt;

sbtnode tree[maxn];

void rrotate(int &t)
{
    int k=tree[t].left;
    if(!k)
    {
        return ;
    }
    tree[t].left=tree[k].right;
    tree[k].right=t;
    tree[k].size=tree[t].size;
    tree[t].size=tree[tree[t].left].size+tree[tree[t].right].size+1;
    t=k;
}

void lrotate(int &t)
{
    int k=tree[t].right;
    if(!k)return;
    tree[t].right=tree[k].left;
    tree[k].left=t;
    tree[k].size=tree[t].size;
    tree[t].size=tree[tree[t].left].size+tree[tree[t].right].size+1;
    t=k;
}

void maintain(int &t,bool flag)
{
    if(!t)return;
    if(!flag)
    {
        if(tree[tree[tree[t].left].left].size>tree[tree[t].right].size)
        {
            rrotate(t);
        }
        else if(tree[tree[tree[t].left].right].size>tree[tree[t].right].size)
        {
            lrotate(tree[t].left);
            rrotate(t);
        }
        else return ;
    }
    else
    {
        if(tree[tree[tree[t].right].right].size>tree[tree[t].left].size)
        {
            lrotate(t);
        }
        else if(tree[tree[tree[t].right].left].size>tree[tree[t].left].size)
        {
            rrotate(tree[t].right);
            lrotate(t);
        }
        else return ;
    }
    maintain(tree[t].left,false);
    maintain(tree[t].right,true);
    maintain(t,false);
    maintain(t,true);
}

void insert(int &t,int v)
{
    if(!t)
    {
        sbttail++;
        tree[sbttail].key=v;
        tree[sbttail].size=1;
        t=sbttail;
    }
    else
    {
        tree[t].size++;
        if(v<tree[t].key)
        {
            insert(tree[t].left,v);
        }
        else
        {
            insert(tree[t].right,v);
        }
        maintain(t,v>=tree[t].key);
    }
}

int del(int &t,int v)
{
    int ret;
    tree[t].size--;
    if(v==tree[t].key||(v<tree[t].key&&tree[t].left==0)||(v>tree[t].key&&tree[t].right==0))
    {
        ret=tree[t].key;
        if(tree[t].left==0||tree[t].right==0)
        {
            t=tree[t].left+tree[t].right;
        }
        else
        {
            tree[t].key=del(tree[t].left,tree[t].key+1);
        }
    }
    else
    {
            if(v<tree[t].key)
            {
                ret=del(tree[t].left,v);
            }
            else
            {
                ret=del(tree[t].right,v);
            }
    }
    return ret;
}

int select(int t,int k)
{
    if(k==tree[tree[t].left].size+1)
    {
        return t;
    }
    if(k<=tree[tree[t].left].size)
    {
        return select(tree[t].left,k);
    }
    else return select(tree[t].right,k-1-tree[tree[t].left].size);
}

int main()
{
    int n,k;
    while(~scanf("%d%d",&n,&k))
    {
        memset(tree,0,sizeof(tree));
        sbttail=0;
        sbt=0;

        char c;
        for(int i=1;i<=n;i++)
        {
            c=getchar();
            while(c!='I'&&c!='Q')
            {
                c=getchar();
            }
            int now;
            if(c=='I')
            {
                scanf("%d",&now);
                insert(sbt,now);
            }
            else
            {
                now=select(sbt,sbttail-k+1);
                printf("%d\n",tree[now].key);
            }
        }
    }
    return 0;
}
### 关于 XTU OJ 平台上的 K-Good Number 问题 #### 题目描述 题目要计算 n 位无前导零的二进制数中,“好数”的数量。所谓“好数”,是指该数的二进制表示中,数码 `1` 的个数于数码 `0` 的个数。 --- #### 解题思路 为了解此问题,可以采用动态规划的方法来高效解决: 1. **状态定义** 定义 `dp[i][j]` 表示 i 位二进制数中,有 j 个 `1` 的所有可能组合的数量[^5]。 2. **转移方程** 对于每一位二进制数,可以选择填入 `0` 或者 `1`: - 填入 `0`: 则当前的状态由上一位少一个位置且相同数量的 `1` 转移而来,即 `dp[i][j] += dp[i-1][j]`。 - 填入 `1`: 当前的状态由上一位少一个位置且 `1` 数量减少一的情况转移而来,即 `dp[i][j] += dp[i-1][j-1]`。 3. **边界条件** 初始化时,当只有一位二进制数时: - 若只有一个 `1` (`dp[1][1]=1`); - 若只有 `0` (`dp[1][0]=1`)。 4. **最终结果** 计算满足条件的结果:对于给定的 n 位二进制数,统计其中 `1` 的个数严格于 `0` 的情况总数。由于最高位不能为 `0` (因为不允许前导零),因此需要特别处理第一位固定为 `1` 后剩余部分的可能性。 --- #### 动态规划实现代码 以下是基于上述分析的 Python 实现代码: ```python def count_good_numbers(n): MOD = 10**9 + 7 # Initialize DP table with zeros dp = [[0]*(n+1) for _ in range(n+1)] # Base case initialization dp[0][0] = 1 # Fill the DP table using recurrence relations for i in range(1, n+1): # For each bit position from 1 to n for j in range(i+1): # Possible number of '1's at this stage if j > 0: dp[i][j] = (dp[i][j] + dp[i-1][j-1]) % MOD # Case when current bit is '1' dp[i][j] = (dp[i][j] + dp[i-1][j]) % MOD # Case when current bit is '0' result = 0 for ones in range((n//2)+1, n+1): # Count cases where '1' exceeds '0' result = (result + dp[n][ones]) % MOD return result # Example usage if __name__ == "__main__": n = int(input()) print(count_good_numbers(n)) ``` --- #### 复杂度分析 - 时间复杂度: \(O(n^2)\), 主要来源于双重循环填充 DP 表格。 - 空间复杂度: \(O(n^2)\), 使用二维数组存储中间状态。 通过优化空间复杂度(仅保留两行数据),可进一步降低内存消耗至 \(O(n)\)。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值