POJ 1442 Black Box

题意:

给你个序列和一串询问  询问前a[i]个数字第i小的是几


思路:

动态的第k值问题  由于区间只增不减所以是水题

利用平衡树解决这类问题

treap是方便编写的类似平衡树的产品

treap方便实现BST的功能  splay更适合于去维护区间


代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<ctime>
#include<cstdlib>
using namespace std;
#define N 30010
#define inf ((1U<<31)-1)
#define L(x) (ch[x][0])
#define R(x) (ch[x][1])

int ch[N][2],val[N],priority[N],num[N],size[N];
int tot,root;

int newnode(int &u,int w)
{
    u=++tot;
    L(u)=R(u)=0;
    priority[u]=rand();
    num[u]=size[u]=1;
    val[u]=w;
    return u;
}

inline void up(int u)
{
    size[u]=size[L(u)]+size[R(u)]+num[u];
}

void rotate(int &u,int kind)
{
    int y=ch[u][kind^1];
    ch[u][kind^1]=ch[y][kind];
    ch[y][kind]=u;
    up(u);
    up(y);
    u=y;
}

int insert(int &u,int w)
{
    if(!u) return newnode(u,w);
    int res,kind;
    if(w==val[u])
    {
        num[u]++;
        res=u;
    }
    else
    {
        kind=(w>val[u]);
        res=insert(ch[u][kind],w);
        if(priority[ch[u][kind]]<priority[u]) rotate(u,kind^1);
    }
    up(u);
    return res;
}

int select(int u,int k)
{
    if(size[L(u)]>=k) return select(L(u),k);
    if(size[L(u)]+num[u]>=k) return val[u];
    return select(R(u),k-size[L(u)]-num[u]);
}

void remove(int &u,int w)
{
    if(val[u]==w)
    {
        if(num[u]>1) num[u]--;
        else if(!L(u)&&!R(u))
        {
            u=0;
            return ;
        }
        else
        {
            int kind=(priority[L(u)]<priority[R(u)]);
            rotate(u,kind);
            remove(u,w);
        }
    }
    else remove(ch[u][w>val[u]],w);
    up(u);
}

void init()
{
    R(0)=L(0)=size[0]=num[0]=val[0]=0;
    priority[0]=inf;
    tot=root=0;
    newnode(root,inf);
}

int n,m;
int a[N],b[N];

int main()
{
    int i,j;
    while(~scanf("%d%d",&n,&m))
    {
        srand(n*5-m+19930909);
        init();
        for(i=1;i<=n;i++) scanf("%d",&a[i]);
        for(j=1;j<=m;j++) scanf("%d",&b[j]);
        for(j=1,i=1;j<=m;j++)
        {
            while(i<=b[j])
            {
                insert(root,a[i]);
                i++;
            }
            printf("%d\n",select(root,j));
        }
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值