洛谷P1165—— 日志分析
见:P1165 日志分析 - 洛谷
题目描述
M 海运公司最近要对旗下仓库的货物进出情况进行统计。
目前他们所拥有的唯一记录就是一个记录集装箱进出情况的日志。
该日志记录了两类操作:第一类操作为集装箱入库操作,
以及该次入库的集装箱重量;第二类操作为集装箱的出库操作。
这些记录都严格按时间顺序排列。
集装箱入库和出库的规则为先进后出,
即每次出库操作出库的集装箱为当前在仓库里所有集装箱中最晚入库的集装箱。
出于分析目的,
分析人员在日志中随机插入了若干第三类操作――查询操作。
分析日志时,
每遇到一次查询操作,
都要报告出当前仓库中最大集装箱的重量。
输入格式
包含 N+1 行:
第一行为一个正整数 N,对应于日志内所含操作的总数。
接下来的 N 行,分别属于以下三种格式之一:
- 格式 1:
0 X
,表示一次集装箱入库操作,正整数 X 表示该次入库的集装箱的重量。 - 格式 2:
1
,表示一次集装箱出库操作,(就当时而言)最后入库的集装箱出库。 - 格式 3:
2
,表示一次查询操作,要求分析程序输出当前仓库内最大集装箱的重量。
当仓库为空时你应该忽略出库操作,当仓库为空查询时你应该输出 0。
输出格式
输出行数等于日志中查询操作的次数。每行为一个整数,表示查询结果。
输入输出样例
in:
13
0 1
0 2
2
0 4
0 2
2
1
2
1
1
2
1
2out:
2
4
4
1
0
说明/提示
数据范围及约定
- 对于 20% 的数据,有 N≤10;
- 对于 40% 的数据,有 N≤1000;
- 对于 100% 的数据,有 1≤N≤200000,1≤X≤108。
前置知识
- 栈
栈是一种后进先出(LIFO,last in first out)的线性表,其限制是仅允许在表的一端进行插入和删除运算
(补:应该是“插入和删除操作”)
您也可以把栈理解成这样:
(当然一个数据结构是不会说话的)
这只想表达三点:
-
堆栈溢出(stack overflow)是致命的,
-
它会导致RE,使用STL里的栈一般不用担心它,
-
如果用STL的栈,需要头文件stack。(或直接用万能头文件)
-
靠近栈底的元素总比更远离栈底的元素更晚出栈
-
栈只可以对栈顶及它以上的一格空间进行修改(但一般手写栈会加上清空栈的函数)
题解主体
看到操作1与操作2就应该知道用栈了吧,
而且是栈的基本操作。
关键就在操作3,
查询最大值。
查询最大值我们一般都是遍历一遍数组然后用“打擂台”
(将每个元素与最大值比较,如果当前元素更大就更新最大值),
手写栈完全可以胜任,
但这不是我们想要的结果。
((*^▽^*):不这样够了我知足了)
怎么可以O(1)查询吗?保证栈内元素不减?
这是可以的。
考虑如下入库顺序:
< 1 , 1 , 4 , 5 , 1 , 4 ,1 , 9 , 1 ,9 >
((*^▽^*):你怎么这么恶臭)
显然它非单调。
我们发现,如果每次入库都query一下,结果是:
< 1 , 1 , 4 , 5 , 5 , 5 ,5 , 9 , 9 ,9 >
它是单调的!
再加上出库看看:
如果出的是一段数值一样的序列的非第一个,那是满足的。
如果是第一个呢?最大值将会被改变!
那也没关系,根据栈的性质,它被弹掉了它前面的也被弹掉了,此时栈顶就是另外的最大值了。
于是我们在压入元素时可以:
如果它比栈顶大,压入它。
如果不是,压入一遍栈顶。
此外,如果栈是空的,不管怎样都要压入它。
先定义一个栈:
stack<int> st;
当输入的==0,时就再输入一个数(x),然后栈.push(这个数);
当输入的==1时就栈.pop()
本题的重难点——最大值(用优先队列也可以,不过有些麻烦):
f[st.size()-1]=max(f[st.size()-2],x);
-
输出:输出f[st.size()-1]就好了(当栈不为空时)为空时就输出0;
双手奉上代码:
#include<bits/stdc++.h>
using namespace std;
stack<int> st;
int n,op,x,f[100005];
int main()
{cin>>n;for(int i=1;i<=n;i++){cin>>op;if(op==0){cin>>x;st.push(x);f[st.size()-1]=max(f[st.size()-2],x);}if(op==1&&!st.empty())st.pop();if(op==2)cout<<f[st.size()-1]<<endl;}return 0;
}
给个赞吧