HDU 4006 The kth great number (求动态第k大值【Treap】)

36 篇文章 0 订阅
3 篇文章 0 订阅

题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=4006
The kth great number

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65768/65768 K (Java/Others)
Total Submission(s): 11885 Accepted Submission(s): 4677

Problem 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

Hint
Xiao Ming won’t ask Xiao Bao the kth great number when the number of the written number is smaller than k. (1=

#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
using namespace std;

struct Node
{
    Node *ch[2];//左右子树
    int r;//随机优先级
    int v;//该点的值
    int s;//该点的节点总数
    Node(int v):v(v)
    {
        ch[0]=ch[1]=NULL;//左右子树初始化为空
        r=rand();//优先级随机
        s=1;//只有本身一个结点
    }
    bool operator <(const Node &rhs)const
    {
        return r<rhs.r;
    }
    int cmp(int x)const
    {
        if(x==v)return -1;
        return x<v?0:1;//0代表左边,1代表右边
    }
    void maintain()//更新结点域
    {
        s=1;
        if(ch[0]!=NULL)s+=ch[0]->s;
        if(ch[1]!=NULL)s+=ch[1]->s;
    }
};
void rotate(Node* &o,int d)//对o结点进行旋转,0代表左旋,1代表右旋,旋转后更新结点域
{
    Node *k=o->ch[d^1];
    o->ch[d^1]=k->ch[d];
    k->ch[d]=o;
    o->maintain();
    k->maintain();
    o=k;
}
void insert(Node* &o,int x)//插入一个值为x的结点
{
    if(o==NULL)o=new Node(x);
    else
    {
        int d=(x<o->v?0:1);//x< o->v 时d=0该节点被插入左边,否则d=1插入右边
        insert(o->ch[d],x);
        if(o->ch[d]->r>o->r)rotate(o,d^1);//如果被插入后优先级比父节点大,要发生旋转
    }
    o->maintain();
}
void remove(Node* &o,int x)//删除一个值为x的节点
{
    int d=o->cmp(x);
    if(d==-1)//d==1时代表代表需删除的节点为当前节点
    {
        Node* u=o;
        if(o->ch[0]!=NULL&&o->ch[1]!=NULL)//左右孩子非空
        {
            int d2=(o->ch[0] > o->ch[1] ?1:0);//左孩子与右孩子谁的优先级比较高
            rotate(o,d2);//谁的高向另外的方向旋转
            remove(o->ch[d2],x);//旋转后删除x节点
        }
        else
        {
            if(o->ch[0]==NULL)o=o->ch[1];//左孩子为空,o指向右孩子
            else o=o->ch[0];//否则指向左孩子
            delete u;
        }
    }
    else
        remove(o->ch[d],x);
    if(o!=NULL)o->maintain();//删除后o有孩子的话更新结点域
}

const int maxc = 500000 + 10;
struct Command
{
    char type;
    int x,p;
} commands[maxc]; //记录要执行的命令


Node *root;//Treap

int kth(Node* o,int k)//查找以o为根节点的子树中的第k大
{
    if(o==NULL || k <= 0 ||k > o->s)return 0;//不合法情况
    int s = (o->ch[1] == NULL ? 0 : o->ch[1]->s);
    if(k==s+1)return o->v;//正好第k大为当前节点
    else if(k<=s)
    {
        return kth(o->ch[1],k);//第k大在右子树上
    }
    else return kth(o->ch[0],k-s-1);//第k大在左子树上
}

const int maxn = 30000+10;
int n,m,a[maxn];

int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        int x;
        root=NULL;
        char str[3];
        for(int i=1;i<=n;i++)
        {
            scanf("%s",str);
            if(str[0]=='I')
            {
              scanf("%d",&x);
              insert(root,x);
            }
            else
            {
                printf("%d\n",kth(root,m));
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值