Mergeable Stack
ZOJ - 4016题目链接
这道题真的很坑爹,一开始做的时候感觉很简单的一道关于栈操作的题,然后就用了stl里的stack结果爆内存了,然后改了三次还是不行,后来还用了string字符串,先是超时后来又爆内存,大概是因为stl里面的容器内存不够时是二倍扩展,每次二倍就指数增长了,然后题目再恰好弄个数据让你一扩展乘2就超过题目要求内存了,真的坑。
后来听说有同学自己写的链式栈过了,因为是用一个申请一个内存,然后写了个答案错误妈的不改了。再后来看了大佬的代码,感觉很巧妙。
思路是把所有数字都存在一个数组a中,然后用三个数组top,Next,bottom分别记录栈顶栈底和栈顶下一个数字在a数组的下标数字,这样最多只用四个3e5的数组不会超内存也不回超时
code:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n,q;
const int maxn = 300005;
int top[maxn],Next[maxn],a[maxn],bottom[maxn];
//a数组记录所有的数,top记录每个栈的栈顶元素在a中的下标,
//Next记录每个栈栈顶的下一个元素在a中的下标,bottom记录栈底元素在a中的下标
int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&q);
int cnt = 0;//a数组的下标
memset(top,0,sizeof(top));
memset(Next,0,sizeof(Next));
memset(bottom,0,sizeof(bottom));//初始化
while(q--){
int op;
scanf("%d",&op);
if(op == 1){
int s,v;
scanf("%d%d",&s,&v);
a[++cnt] = v;//元素放入数组a
if(bottom[s] == 0)//如果这个栈栈底为空,栈底等于这个元素在a中的下标
bottom[s] = cnt;
Next[cnt] = top[s];//这个下标cnt下一个元素指向原本的栈顶元素在a中下标
top[s] = cnt;//更新栈顶
}
if(op == 2){
int s;
scanf("%d",&s);
if(top[s]){//如果栈不空
printf("%d\n",a[top[s]]);//输出a中这个位置的元素
top[s] = Next[top[s]];//指向下一个,相当于弹出栈顶
if(top[s] == 0) bottom[s] = 0;//如果空了,bottom也变为空
}
else//如果栈空输出empty
printf("EMPTY\n");
}
if(op == 3){
int s,t;
scanf("%d%d",&s,&t);
if(top[t] != 0){
if(bottom[s] == 0) bottom[s] = bottom[t];//如果s是空的,s的底就是t的底
Next[bottom[t]] = top[s];//t的底部指向s的顶
top[s] = top[t];//s的顶变成了t的顶
}
bottom[t] = top[t] = 0;//t移动后清空
}
}
}
return 0;
}