1057. Stack (30)



时间限制


100 ms






内存限制


65536 kB






代码长度限制


16000 B






判题程序


Standard



作者


CHEN, Yue





Stack is one of the most fundamental data structures, which is based on the principle of Last In First Out (LIFO). The basic operations include Push (inserting an element onto the top position) and Pop (deleting the top element). Now you are supposed to implement a stack with an extra operation: PeekMedian -- return the median value of all the elements in the stack. With N elements, the median value is defined to be the (N/2)-th smallest element if N is even, or ((N+1)/2)-th if N is odd.
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (<= 105). Then N lines follow, each contains a command in one of the following 3 formats:Push
key

Pop

PeekMedian
where key is a positive integer no more than 105.
Output Specification:
For each Push command, insert key into the stack and output nothing. For each Pop or PeekMedian command, print in a line the corresponding returned value. If the command is invalid, print "Invalid" instead.




Sample Input:
17
Pop
PeekMedian
Push 3
PeekMedian
Push 2
PeekMedian
Push 1
PeekMedian
Pop
Pop
Push 5
Push 4
PeekMedian
Pop
Pop
Pop
Pop
Sample Output:
Invalid
Invalid
3
2
2
1
2
4
4
5
3
Invalid






这题和以前做的mystack是一样,但是以前的算法结构的测试数据可能比较少,我当时的链表模式的通关了,这次我就学他们用的树状数组写的。然后还看到另一个是两个multiset(这个目前还没有用过,默认升序的好像是这样)的和stack(这里的也有用到,就是后进先出)的


输入N;接着N行命令,push进入一个,pop输出最后进一个数并让他出来,Peekmedian输出这些还在栈中的从小到大的中间的那个数,偶数个第N/2,奇数个(N+1)/2;






以前的链表的,在此处超时3个:http://xujiayu317.blog.163.com/blog/static/254752092014431105127155/


评测结果

时间

结果

得分

题目

语言

用时(ms)

内存(kB)

用户

8月02日

17:22

答案正确

​30​

​1057​

​C++ (g++ 4.7.2)​

25

1332

​datrilla​

测试点

测试点

结果

用时(ms)

内存(kB)

得分/满分

0

答案正确

1

636

15/15

1

答案正确

25

1204

5/5

2

答案正确

25

1152

5/5

3

答案正确

25

1332

3/3

4

答案正确

1

692

2/2

#include<iostream>   
#include<stack>
#define MAX 100001/*不多于100000_no more than 10^5.*/
using namespace std;
/*htt p://duanple.blog.163.com/blog/static/7097176720081131113145832/*/
int lowBit_from_right_to_left_first_One(int key)
{
return key&(-key);/*例子:比如二进制(key补码)000110 那么返回000010这个值是2;级别2=2^1;
100011 那么返回000001这个值是1;级别1=2^0;
101000 那么返回001000这个值是8;级别8=2^3;
000000 那么返回000000这个值是0;级别0;
------------------------------------
等价于key&(key^(key-1));
key不为零时最高能被2的k次方整除,结果就等于2^k;
当key结果为零时,结果为零;
----------------------------------------------
key&(-key) 一种情况key为零,结果为0;
另一种情况假如key为正数,-key为负数在计算机中用补码表示
(-key补=key的原从低位(右边向左),在没有遇到第一个1包括第一个1都保持不变,接下去直到符号位包括符号位全变反[1变0,0变1])
--------------------------------------------------
key&(key^(key-1)对于key与key-1的区别在于key减1的时候像高位借位,而借位的情况在二进制中当key的最低位为0,而要减去的是1,
显然,会被借位的最高位【从低位(右边向左),在遇到的第一个1】,所以key和key-1在这个1的左边本身全一样,在1的右边包括1全不一样;
key^(异或)key-1;按位异或,没有进位的加(同清零,不同置1),接着和原来的key按位与&没有进位的乘(1&1=1其他都为0)
显然key和key^(key-1只有刚刚1的那个位置一样且都为1;
*/
}
void insertCountkey(int*Countkey,int key,int add_dec)
{
while (key <= MAX)
{
Countkey[key] += add_dec;
key += lowBit_from_right_to_left_first_One(key);
}/*设key的级别为2^k实现Countkey[key] 增加一个add或减少一个dec
接着对于级别大于2^k的第一个newkey实现Countkey[newkey]增加一个add标记或减少一个dec
注释:这些大于2^k的newkey=2^(k+1);2^(k+2)……<=MAX;
所以显然,只有Countkey[2^k]包含所有1<key<=2^k的数量
Countkey[2^k+1]=Countkey[2^k+1];只包含他自己即key=2^k+1的数量;
Countkey[2^k+2]=包含key=2^k+1和key=2^k+2的数量;
结合下面的low_and_函数,假如此时
low_and_(int*Countkey, int 2^k)那么直接获得sum+=Countkey[2^k],key=0;结束时sum=所有1<key<=2^k的数量
low_and_(int*Countkey, int 2^k+1)那么会先sum+=Countkey[2^k+1],key=2^k;接着sum+=Countkey[2^k],key=0;结束时sum=所有1<key<=2^k+1的数量;
low_and_(int*Countkey, int 2^k+2)那么会先sum+=Countkey[2^k+2],key=2^k;接着sum+=Countkey[2^k],key=0;结束时sum=所有1<key<=2^k+2的数量;
*/
}
int low_and_(int*Countkey, int key)
{
int sum = 0;
while (key > 0)
{
sum += Countkey[key];
key -= lowBit_from_right_to_left_first_One(key);
}
return sum;/*
下面的2^k是不断变动的。
如果这一key是n*2^k(n为奇数),那么会实现sum+和key-;
如果这一key已经是2^k,那么最后一次key-=lowBit_from_right_to_left_first_One;
(key=0;结束,由Binary indexed tree-树状数组 特性知道,此时的sum=Countkey[2^k]+……+Countkey[key最开始];

*/
}
int findmid(int*Countkey,int mid)
{
int low = 0, high = MAX ;
int midtemp,countSum;
while (low <= high)
{
midtemp = (low + high) / 2;
countSum = low_and_(Countkey, midtemp);
if (countSum>= mid)high = midtemp-1;
else low = midtemp + 1;
}
return low;
}
void Push(stack<int>*Last_In_First_Out, int*Countkey)
{
int key;
scanf("%d", &key);
(*Last_In_First_Out).push(key);
insertCountkey(Countkey,key,1);
}
void Pop(stack<int>*Last_In_First_Out, int*Countkey)
{
if ((*Last_In_First_Out).empty())printf("Invalid\n");
else
{
printf("%d\n",Last_In_First_Out->top());
insertCountkey(Countkey, Last_In_First_Out->top(), -1);
Last_In_First_Out->pop();
}
}
void PeekMedian(stack<int>*Last_In_First_Out, int*Countkey)
{

if ((*Last_In_First_Out).empty())printf("Invalid\n");
else
{
printf("%d\n",findmid(Countkey,((*Last_In_First_Out).size() + 1) / 2));
}
}
int main()
{
stack<int> Last_In_First_Out;
int Countkey[MAX]={0};
int N;
char order[11];
scanf("%d", &N);
while (N--)
{
scanf("%s",order);
switch(order[1])
{
case 'u':
Push(&Last_In_First_Out, Countkey);
break;
case 'o':
Pop(&Last_In_First_Out, Countkey);
break;
case 'e':
PeekMedian(&Last_In_First_Out, Countkey);
break;
}
}
system("pause");
return 0;
}