题目

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

又到饭点了,SK同学靠着惯性走到了食堂,但长长的队伍顿时让他失去了食欲。突然,他注意到某个窗口前的队伍里明显存在插队的现象,于是他默默记录下了同学们进队和出队的变化。

对于进队,SK同学只知道队伍里多了一个人,并不知道新来的人是老老实实站到了队尾还是插到了队伍里的某个位置;对于出队,SK同学能确定是队伍里站在最前面的人出队了。

初始时队伍为空,给出n条队伍进出的信息,保证已经出队的同学不会再入队,并且最终队伍也为空,现在SK同学想知道有多少不插队的好同学。

输入描述:

第一行是一个正整数T(≤ 5),表示测试数据的组数, 对于每组测试数据, 第一行是一个整数n(1≤ n ≤ 100000),表示这个队伍进出的信息数, 接下来n行,每行是两个字符串Opt Name,其中Opt为"in"代表进队,"out"代表出队,Name为进队或出队的人的名字, 所有信息按照时间顺序给出,名字由英文字母和阿拉伯数字组成,长度不超过10,保证每个人的名字各不相同。

输出描述:

对于每组测试数据,输出一行,包含一个整数,表示不插队的人数。

示例1

输入

1
6
in quailty
in hwq1352249
out hwq1352249
in zhuaiballl
out quailty
out zhuaiballl

输出

2

题解

这道题目说实话感觉比较难

从以下分析入手:

Keep In Line_via牛客网_栈



判断有没有插队

将每一个人按照入队顺序进行编号,按照出队顺序写出编号

某一处编号是不是小于所有的它的后面的编号

yes

这个人没有插队

no

这个人插队了

考虑使用单调栈进行快速判断

单调栈详解

1.用于求数列中每一个数往右数直到大于它的数的个数问题以及推广

2.用于根据剩余的结果来求有没有插队的问题

代码

#include <iostream>
#include <string>
#include <map>
#include <stack>
using namespace std;
int out[50009];
int main()
{
ios::sync_with_stdio(false);
int T;
cin >> T;
while (T--)
{
map<string, int>mp;
int no = 0;//入队时候的编号
int cnt = 0;//出队时候的计数
int n;
cin >> n;
for (int i = 0; i < n; i++)
{
string name, option;
cin >> option >> name;
if (option == "in")
{
mp[name] = no++;
}
else
{
out[cnt++] = mp[name];
}

}
mp.clear();
stack<int>st;
for (int i = 0, pos = 0; i < n / 2; i++)
{

if (st.empty() || out[pos] > st.top())
{
st.push(out[pos]);
}
else
{
while (!st.empty() && out[pos] <= st.top())
{
st.pop();
}
st.push(out[pos]);
}
pos++;
}
cout << st.size() << endl;
}
return 0;
}