Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 10890   Accepted: 4446

Description

Our Black Box represents a primitive database. It can save an integer array and has a special i variable. At the initial moment Black Box is empty and i equals 0. This Black Box processes a sequence of commands (transactions). There are two types of transactions: 



ADD (x): put element x into Black Box; 

GET: increase i by 1 and give an i-minimum out of all integers containing in the Black Box. Keep in mind that i-minimum is a number located at i-th place after Black Box elements sorting by non- descending. 



Let us examine a possible sequence of 11 transactions: 



Example 1

N Transaction i Black Box contents after transaction Answer 

      (elements are arranged by non-descending)   

1 ADD(3)      0 3   

2 GET         1 3                                    3 

3 ADD(1)      1 1, 3   

4 GET         2 1, 3                                 3 

5 ADD(-4)     2 -4, 1, 3   

6 ADD(2)      2 -4, 1, 2, 3   

7 ADD(8)      2 -4, 1, 2, 3, 8   

8 ADD(-1000)  2 -1000, -4, 1, 2, 3, 8   

9 GET         3 -1000, -4, 1, 2, 3, 8                1 

10 GET        4 -1000, -4, 1, 2, 3, 8                2 

11 ADD(2)     4 -1000, -4, 1, 2, 2, 3, 8   

It is required to work out an efficient algorithm which treats a given sequence of transactions. The maximum number of ADD and GET transactions: 30000 of each type. 





Let us describe the sequence of transactions by two integer arrays: 





1. A(1), A(2), ..., A(M): a sequence of elements which are being included into Black Box. A values are integers not exceeding 2 000 000 000 by their absolute value, M <= 30000. For the Example we have A=(3, 1, -4, 2, 8, -1000, 2). 



2. u(1), u(2), ..., u(N): a sequence setting a number of elements which are being included into Black Box at the moment of first, second, ... and N-transaction GET. For the Example we have u=(1, 2, 6, 6). 



The Black Box algorithm supposes that natural number sequence u(1), u(2), ..., u(N) is sorted in non-descending order, N <= M and for each p (1 <= p <= N) an inequality p <= u(p) <= M is valid. It follows from the fact that for the p-element of our u sequence
we perform a GET transaction giving p-minimum number from our A(1), A(2), ..., A(u(p)) sequence. 




Input

Input contains (in given order): M, N, A(1), A(2), ..., A(M), u(1), u(2), ..., u(N). All numbers are divided by spaces and (or) carriage return characters.

Output

Write to the output Black Box answers sequence for a given sequence of transactions, one number each line.

Sample Input

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

Sample Output

3
3
1
2

Source

【题解】

一开始看错题目,以为是把i加入到平衡树中,然后在平衡树中把i的值加1,然后调整i在平衡树中的位置,然后再输出第i小的值。。。

所以程序中多了一个删除平衡树中某个点的操作。(就当做学习了);

真正的题意是,每次询问的时候递增i就好,然后输出第i小的数(这个i并不在平衡树里面!);

用的是sbt树。

sbt树因为本身就是用size来保持平衡的,所以求第k小的数的时候很方便;

/*

关于这个程序中的删除操作。需要用递归来实现。可能删除了某一个数字之后,拿来替换的节点也要进行复杂度删除操作(但是操作是相同的);具体的实现方式看程序;

*/

【代码】

#include <cstdio>

int l[100000],r[100000],size[100000],totn = 0,key[100000],root =0;
int a[40000],b[40000]; void right_rotation(int &t) // 右旋代码。
{
int k = l[t];//先将根节点的左儿子提取出来。
l[t] = r[k];//然后把根节点的左儿子的右子树接在根节点的左子树位置
r[k] = t;//然后把原来的根节点的左儿子往右上旋转代替原来的根节点成为新的根节点。
size[k] = size[t];//新的根节点等于原来的根节点的大小
size[t] = size[l[t]]+size[r[t]]+1;//l[t]就是被转移过来的r[k(原来的)]。然后t的右子树是没有发生变化的。
t = k;//新的根节点变成了t。
} void left_rotation(int &t)//左旋代码
{
int k = r[t]; //先获取根节点的右儿子。
r[t] = l[k];//然后用根节点的右儿子的左子树来代替根节点的右子树;
l[k] = t;//然后把根节点的右儿子往左上的方向提上来代替原来的根节点
size[k] = size[t];//k成为了新的根节点,它的大小和原来的根节点是一样的。
size[t] = size[r[t]]+size[l[t]]+1;//t的左子树没有发生变化,然后右子树已经修改过了。直接加上相应的大小再加上自身即可
t = k;//根节点发生了变化变成了k
} void maintain(int &t,bool flag)//maintain函数,看SBT树的实现的话绕道。这里只写一下大概思路
{
if (flag) //往左调整
{
if (size[l[l[t]]] > size[r[t]])//这是/型的情况
right_rotation(t);
else
if (size[r[l[t]]] > size[r[t]])//这是<型的情况
{
left_rotation(l[t]);
right_rotation(t);
}
else
return;//如果都不是的话就结束递归
}
else
{
if (size[r[r[t]]] > size[l[t]])//这是\型的情况
{
left_rotation(t);
}
else
if (size[l[r[t]]] > size[l[t]])//这是>型的情况。
{
right_rotation(r[t]);
left_rotation(t);
}
else
return;
}
maintain(l[t],true);//可以这样理解,如果是\型,原来的根节点的右子树变成了原来的根节点的右儿子的左子树
//而原来的根节点的左子树不变。
//那么是原来的左子树比较大还是新的右子树比较大呢?
//当然是原来的左子树比较大,所以原来的根节点变成根节点的左儿子之后,调整的话应该是/型或<型的应该往左
maintain(r[t],false);//往右的同理。
maintain(t,true);//这两句是因为左右子树如果都发生了变化,需要重新维护一下根节点的子树。
maintain(t,false);//既然不知道方向,就两个方向都试试
} void insert(int &t,int data)//把data这个元素插入到平衡树中。
{
if (t==0)//如果是一个之前未到达过的节点则直接新创建一个节点
{
t=++totn;
l[t] = r[t] = 0;//把这个data记录在这个位置
size[t] = 1;//这个节点的大小为1
key[t] = data;
}
else
{
size[t]++;//否则就判断要往哪里走,不论往哪里走,以t为根节点的树的大小肯定递增了
if (data<key[t])//如果小于它就往左走
insert(l[t],data);
else//否则往右走
insert(r[t],data);
maintain(t,data<key[t]);//尝试调整平衡树,那个比较的表达式可以确定调整的方向。
}
} int k_th(int t, int k) //寻找k小数
{
if (size[l[t]]+1 == k)//如果比key[t]小的数的数目+1就是k,那么这个key[t]就是所求的数
return key[t];
else
if (size[l[t]] +1 > k)//如果比它小的数+1大于了k,那么就继续往左找第k小数
return k_th(l[t],k);
else
if (size[l[t]]+1<k)//如果比它小的数+1小于k,那么问题转换成往右找第(k-(size[l[t]]+1))小的数。
return k_th(r[t],k-(size[l[t]]+1));
} void de_lete(int data,int &t) //这是删除平衡树中某个节点的过程;
{
size[t]--;//因为这个节点肯定在以t为根的树下面。所以删除后,它的大小会递减。
if (key[t] == data)//如果找到了要删除的元素。
{
if (l[t] ==0 && r[t] == 0)//如果它没有左子树或右子树
t = 0;//那么就直接把这个节点置空
else
if (l[t] == 0 && r[t]!=0)//如果左子树为空,右子树不为空
t = r[t];//就把这个节点去掉,用右子树来接在下面。
else
if (l[t] != 0 && r[t] == 0)//如果左子树不为空,右子树为空
t = l[t];//则直接把这个节点去掉,把左子树接在下面。
else
if (l[t]!=0 && r[t]!=0)//如果左右子树都不为空。
{
int temp = r[t];//先记录这个节点的右儿子
while (l[temp]) temp = l[temp];//然后这个右儿子不断地往下找左儿子。
//这样可以找到一个合适的key放在t的位置。
//它满足<=r[t],且一定小于以r[t]为根的子树中的所有节点。满足平衡树定义。
key[t] = key[temp];//直接把那个合适的key值赋值到这个位置。
de_lete(key[temp],r[t]);//然后调用递归,把那个合适的key值所在的位置的节点去掉。
//不能单纯就去掉这个节点,因为其可能有右子树。另外,你一直往左下走,实际上没有递减
//size的值。。所以要重新从r[t]开始往下走。
/*
可以这样写;
小数据测试过。
int temp = r[t];
int pre = temp;
size[temp]--;
while (l[temp])
{
pre = temp;
temp = l[temp];
size[temp]--;
}
while结束之后temp肯定没有左子树了。
就判断一下有没有右子树;
if (r[temp]==0 && temp!=r[t])
l[pre] = 0;
else
if (r[temp] !=0)
l[pre] = r[temp];
这样就可以不用递归了。
*/
}
}
else
if (data<key[t])//如果要删除的值小于这个节点的key值,则往左走
de_lete(data,l[t]);
else//否则往右走。
de_lete(data,r[t]);
} int main()
{
//freopen("rush.txt","r",stdin);
//freopen("rush_out.txt","w",stdout);
int now = 0;
int n,m;
scanf("%d%d",&n,&m); //输入n和m
for (int i = 1;i <= n;i++) //把两个数组都输入
scanf("%d",&a[i]);
for (int i = 1;i <= m;i++)
scanf("%d",&b[i]);
int j = 1;//这是b数组的指针。
for (int i = 1;i <= n;i++)
{
insert(root,a[i]);//把ai这个元素插入到平衡树中
while (b[j]==i)//如果要询问的是在第i个,则输出询问
{
now++;//递增要输出的是第几小的树。。
printf("%d\n",k_th(root,now));//输出
j++;//指针指向下一个。
}
}
/*
下面这个东西是注释的内容。是我用来测试删除,添加和求第k小数的东西。
scanf("%s",op);
while (op[0]!='E')
{
scanf("%d",&a);
if (op[0] == 'A')
insert(root,a);
else
if (op[0] == 'F')
printf("%d\n",k_th(root,a));
else
if (op[0] == 'D')
de_lete(a,root);
scanf("%s",op);
}
*/
return 0;
}

【poj1442】Black Box的更多相关文章

  1. 【POJ1442】【Treap】Black Box

    Description Our Black Box represents a primitive database. It can save an integer array and has a sp ...

  2. 【优先队列】POJ1442-Black Box

    [思路] 建立一个小堆和一个大堆.大堆用来存放第1..index-1大的数,其余数存放在大堆,小堆的堆顶元素便是我们要求出的第index大的数.每次插入一个A(n),必须保证大堆中数字数目不变,故先插 ...

  3. 【hihocoder】 Magic Box

    题目1 : Magic Box 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 The circus clown Sunny has a magic box. When ...

  4. 【前端】display: box布局教程 [转]

    css display:box 新属性   一.display:box; 在元素上设置该属性,可使其子代排列在同一水平上,类似display:inline-block;. 二.可在其子代设置如下属性 ...

  5. 【转载】Virtual Box下配置Host-Only联网方式详解

    其实网络这类相关的文章很多,我只是想结合自己的实际情况,把我的经验写下来,给那些需要的人们吧. 主机:windows 7 虚拟机:CentOS6.0 VirtualBox:4.2.0 虚拟机在安装好之 ...

  6. 【Ubuntu】Vritual Box 复制方式克隆

    重装系统后之前安装的虚拟机的镜像全都不见了 ,因为重装系统盘C盘会全部重新被格式化. VtritualBox如果没有指定虚拟机存放位置,默认是会放在C盘的,C:\Users\Administrator ...

  7. 【Ruby】【高级编程】面向对象

    # [[面向对象]]#[实例变量]=begin实例变量是类属性,它们在使用类创建对象时就编程对象的属性.每个对象的属性是单独赋值的,和其他对象之间不共享.在类的内部,使用@运算符访问这些属性,在类的外 ...

  8. 【BZOJ5138】[Usaco2017 Dec]Push a Box(强连通分量)

    [BZOJ5138][Usaco2017 Dec]Push a Box(强连通分量) 题面 BZOJ 洛谷 题解 这题是今天看到萝卜在做然后他一眼秒了,我太菜了不会做,所以就来做做. 首先看完题目,是 ...

  9. 【荐】利用NAT、Host-Only双虚拟网卡,实现Virtual Box中CentOS5.x联网

    一.虚拟机与主机互联,通常有三种方式,详细介绍请看: VMware虚拟机三种网络模式(Bridged,Nat,Host-only)区别详解 二.通过网络共享,Host-Only联网,详细案例请看: W ...

随机推荐

  1. Spider_lxml

    xpath工具(解析) xpath 在XML文档中查找信息的语言,同样适用于HTML文档的检索 xpath辅助工具 Chrome插件 :XPath Helper 打开 :Ctrl + Shift + ...

  2. ubuntu-安装中文拼音输入法

    一下内容转载自http://blog.chinaunix.net/uid-24410388-id-3501873.html 自己验证了可用.转载了,已留做日后使用 步骤: step1:安装ibus所需 ...

  3. 13.constexpr

    #include <iostream> using namespace std; //声明返回值为常量表达式 constexpr int get() { ; return num; } v ...

  4. 1.16 Python基础知识 - 装饰器初识

    Python中的装饰器就是函数,作用就是包装其他函数,为他们起到修饰作用.在不修改源代码的情况下,为这些函数额外添加一些功能,像日志记录,性能测试等.一个函数可以使用多个装饰器,产生的结果与装饰器的位 ...

  5. 右键菜单添加Total Commander

    Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\Folder\shell\OpeninTC]@="使用TotalCmd打开(& ...

  6. 最小二乘法,python3实现

    https://www.cnblogs.com/BlogOfMr-Leo/p/8627311.html                      [用的是库函数] https://blog.csdn. ...

  7. JAVA开发类似冒险岛的游戏Part1

    JAVA开发类似冒险岛的游戏Part1 一.总结 二.JAVA开发类似冒险岛的游戏Part1 初学嘛) ,不过总的来说这个程序还是很有意思的.这里我重新再整理了一下,希望能帮助到其他想要开发类似程序的 ...

  8. 编程一一C语言问题,指针函数与函数指针

    资料来源于网上: 一.指针函数:指返回值是指针的函数      类型标识符    *函数名(参数表)       int *f(x,y); 首先它是一个函数,只不过这个函数的返回值是一个地址值.函数返 ...

  9. VMware Windows安装详细过程(详细图解)

    说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家! 一.概论 简介:虚拟机(Virtual Machine)指通过软件模拟的具有完整硬件系统功能的.运行在一个完全隔离环境中的完整计算 ...

  10. 细说GCD

    http://blog.csdn.net/hsf_study/article/details/51637453