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

題目鏈接: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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章