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

来源:互联网 发布:占卜软件哪个好 编辑:程序博客网 时间:2024/05/16 02:54

题目链接: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;//Treapint 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;}
原创粉丝点击