poj 1442 第K小数(输入的数可能有重复)

题目意思很简单直接拿样例来解释吧

7 4
3 1 -4 2 8 -1000 2
1 2 6 6

输入 n = 7 m =4,然后第一行输入n个数,然后另一行输入m个数

index = 1

1:输出n个数中前1个数中的第Index(1)小值

index=2

2:输出n个数中前2个数中的第index(2)小值

index=3

6:输出n个数中前6个数中的第index(3)小值

index=4

6:输出n个数中前6个数中的第index(4)小值

输入保证m个数单调递增


我这里就直接上Treap的模板(主要是为了我以后复习用)

数组模拟版:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <ctime>
using namespace std;
#define LL long long
const int N = 100005;

struct Treap
{
    //num表示当前节点孩子的个数
    int data,fix,num,cnt;
    int l,r;
} tree[N];

int size,root;

void left_rat(int &x)//旋转之后x都会成为当前子树的根
{
    int y = tree[x].r;
    tree[x].r = tree[y].l;
    tree[y].l = x;
    x = y;

    y = tree[x].l;
    tree[y].num = tree[tree[y].l].num + tree[tree[y].r].num + tree[y].cnt;
    tree[x].num = tree[tree[x].l].num + tree[tree[x].r].num + tree[x].cnt;
}

void right_rat(int &x)//这里num的计算可以画图理解
{
    int y = tree[x].l;

    tree[x].num = tree[tree[x].r].num + tree[tree[y].r].num + tree[x].cnt;
    tree[y].num = tree[tree[y].l].num + tree[x].num + tree[y].cnt;

    tree[x].l = tree[y].r;
    tree[y].r = x;
    x = y;

    y = tree[x].l;
    tree[y].num = tree[tree[y].l].num + tree[tree[y].r].num + tree[y].cnt;
    tree[x].num = tree[tree[x].l].num + tree[tree[x].r].num + tree[x].cnt;
}

void insert(int &x,int data)//注意递归的时候父节点的tree[x].num也要++,开始的时候没有注意这个
{
    if(x == 0) //null
    {
        x = ++size;//增加一个节点
        tree[x].data = data;
        tree[x].l = tree[x].r = 0;
        tree[x].num = 1;
        tree[x].cnt = 1;
        tree[x].fix = rand();
    }
    else if(data < tree[x].data)
    {
        ++tree[x].num;
        insert(tree[x].l,data);
        if(tree[x].fix < tree[tree[x].l].fix) right_rat(x);
    }
    else if(data > tree[x].data)
    {
        ++tree[x].num;
        insert(tree[x].r,data);
        if(tree[x].fix < tree[tree[x].r].fix) left_rat(x);
    }
    else if(data == tree[x].data)
    {
        ++tree[x].cnt;
        ++tree[x].num;
    }
}

void remove(int &x,int data) //这里是直到x->cnt=1的时候才删除节点x,而不是不管x->cnt就直接删除,这里的删除操作没有验证过
{
    if(x == 0) return;//null
    else if(data < tree[x].data)//递归的时候也要tree[x].num--
    {
        --tree[x].num;
        remove(tree[x].l,data);
    }
    else if(data > tree[x].data)
    {
        --tree[x].num;
        remove(tree[x].r,data);
    }
    else if(data == tree[x].data && tree[x].cnt > 1)
    {
        tree[x].cnt --;
        tree[x].num --;
    }
    else if(data == tree[x].data && tree[x].cnt == 1)
    {
        tree[x].cnt --;
        tree[x].num --;
        if(tree[x].l == 0 && tree[x].r == 0) x = 0;
        else if(tree[x].l == 0) x= tree[x].r;
        else if(tree[x].r == 0) x = tree[x].l;
        else
        {
            if(tree[tree[x].l].fix > tree[tree[x].r].fix)
            {
                right_rat(x);//先旋转,把要删的结点不断选到叶子处,然后再删除
                remove(tree[x].r,data);
            }
            else
            {
                left_rat(x);
                remove(tree[x].l,data);
            }
        }
    }
}

int query(int &x,int k)
{
    if(k < tree[tree[x].l].num + 1)
        return query(tree[x].l,k);
    else if(k > tree[tree[x].l].num + tree[x].cnt)
        return query(tree[x].r,k-(tree[tree[x].l].num + tree[x].cnt));
    else return tree[x].data;
}

int a[30010];

int main()
{
    int n,m,pos;
    srand(100);
    root = size = 0;
    scanf("%d %d",&n,&m);
    for(int i =1 ; i<= n ; i++) scanf("%d",&a[i]);
    int index = 0;
    for(int i = 0 ; i < m ; i ++)
    {
        scanf("%d",&pos);
        for(int j = index + 1 ; j <= pos ; j ++)
            insert(root,a[j]);
        //  tree.inorder(tree.root);
        //cout<<endl;
        index = pos;
        printf("%d\n",query(root,i+1));
    }
    return 0;
}


C++指针版:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <ctime>
#include <queue>
using namespace std;
const int MAXN = ~0U>>1;

class Treap
{
public:
    struct Item
    {
        int element,size,times,fix;
        Item *left,*right;
        Item(int e) : element(e),size(1),times(1),fix(rand()) {}
        inline int lsize()
        {
            return left?left->size:0;
        }
        inline int rsize()
        {
            return right?right->size:0;
        }
    }*root,*null;

    Treap()
    {
        null = new Item(MAXN);
        null->size = null->times = 0;
        null->fix = rand();
        null->element = MAXN;
        root = null->left = null->right = null;
    }

    // left
    void ZAG(Item*& x)
    {
        Item *y = x->right;
        x->right = y->left;
        y->left = x;
        x = y;

        y = x->left;
        y->size = y->lsize() + y->rsize() + y->times;
        x->size = x->lsize() + x->rsize() + x->times;
    }

    // right
    void ZIG(Item*& x)
    {
        Item *y = x->left;
        x->size = y->rsize() + x->rsize() + x->times;
        y->size = y->lsize() + x->size + y->times;
        x->left = y->right;
        y->right = x;
        x = y;

        y = x->left;
        y->size = y->lsize() + y->rsize() + y->times;
        x->size = x->lsize() + x->rsize() + x->times;
    }

    // insert
    void Insert(Item*& x,int e)
    {
        if (x == null)
        {
            x = new Item(e);
            x->element = e;
            x->fix = rand();
            x->times = x->size = 1;
            x->left = x->right = null;
        }
        else if (e < x->element)
        {
            x->size ++;
            Insert(x->left,e);
            if (x->left->fix < x->fix)
                ZIG(x);
        }
        else if (e > x->element)
        {
            x->size ++;
            Insert(x->right,e);
            if (x->right->fix < x->fix)
                ZAG(x);
        }
        else if(e ==x->element)
        {
            ++x->times;
            ++x->size;
        }
    }

    // remove
    void Remove(Item*& x,int e)
    {
        if (x == null)
            return;
        if (e < x->element)//递归的时候注意x->size--
        {
            x->size --;
            Remove(x->left,e);
        }
        else if (e > x->element)
        {
            x->size --;
            Remove(x->right,e);
        }
        else if (e == x->element && x->times > 1)
        {
            x->times--;
            x->size--;
        }
        else if(x->element == e && x->times == 1) //当且仅当x->times==1
        {
            x->times--;
            x->size --;
            if (x->left == null || x->right == null)
            {
                Item *y = x;
                x = (x->left != null)?x->left:x->right;
                delete y;
            }
            else
            {
                if (x->left->fix < x->right->fix)
                {
                    ZIG(x);
                    Remove(x->right,e);
                }
                else
                {
                    ZAG(x);
                    Remove(x->left,e);
                }
            }
        }
    }

    // find min
    int FindMin()
    {
        Item *x;
        for (x = root; x->left != null; x = x->left);
        return x->element;
    }

    //find max
    int FindMax()
    {
        Item *x;
        for (x = root; x->right != null; x = x->right);
        return x->element;
    }

    // Predecessor
    Item* Pred(Item* x,Item* y,int e)
    {
        if (x == null)
            return y;
        if (e < x->element)
            return Pred(x->left,y,e);
        return Pred(x->right,x,e);
    }

    // Successor
    Item* Succ(Item* x,Item* y,int e)
    {
        if (x == null)
            return y;
        if (e <= x->element)
            return Succ(x->left,x,e);
        return Succ(x->right,y,e);
    }

    // Select
    Item* Select(Item* x,int n)
    {
        if(n >= x->left->size + 1 && n <= x->left->size + x->times)
            return x;
        else if(n <= x->left->size)
            return Select(x->left,n);
        else return Select(x->right,n - x->left->size - x->times);
    }

    // Rank
    int Rank(Item* x,int e)
    {
        if (e < x->element)
            return Rank(x->left,e);
        else if (e > x->element)
            return Rank(x->right,e) + x->left->size + x->times;
        return x->left->size + 1;
    }

    int count(int e)
    {
        Item *p = Pred(root,null,e);
        Item *s = Succ(root,null,e);
        return min(abs(p->element - e),abs(s->element - e));
    }

    int solve(Item *x,int n)
    {
        Item *t = Select(x,n);
        return t->element;
    }

    void inorder(Item *x)
    {
        if(x==null) return;
        else
        {
            inorder(x->left);
            cout<<x->element<<" "<<x->times<<" "<<x->size<<" "<<x->fix<<" ";
            inorder(x->right);
        }
    }

};

int a[30010];
int main()
{
    int n,m,pos;
    srand(100);

    scanf("%d %d",&n,&m);
    Treap tree;
    for(int i =1 ; i<= n ; i++) scanf("%d",&a[i]);
    int index = 0;
    for(int i = 0 ; i < m ; i ++)
    {
        scanf("%d",&pos);
        for(int j = index + 1 ; j <= pos ; j ++)
            tree.Insert(tree.root,a[j]);
      //  tree.inorder(tree.root);
        //cout<<endl;
        index = pos;
        printf("%d\n",tree.solve(tree.root,i+1));
    }
    return 0;
}

这题可以用STL中的优先队列(最小堆和最大堆)维护来解决,可以去研究下。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值