单调队列一步到位)
思路
首先一看!有个查询操作,还有个添加操作,要找倒数L位的最大值。再一看操作的个数M <= 2e5,那么每次都查询都对后面L位找最大显然就不现实了。(优先队列破产)
虽然觉得不现实,但是还是用了(因为能混点分嘛)。
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int m, d;
int main()
{
vector<int> v;
cin >> m >> d;
int t = 0;
for(int i = 0; i < m; i++)
{
string x; int k;
cin >> x >> k;
if(x[0] == 'A')
{
v.push_back((k + t) % d);
}
if(x[0] == 'Q')
{
priority_queue <int> q;
int j = 0;
while(k--)
{
j++;
q.push(v[v.size() - j]);
}
cout << q.top() << endl;
t = q.top();
}
}
return 0;
}
然后就非常光荣的斩获了
TLE 30分
接着就洗心革面换上今天学的单调队列了。
我们用例子来讲会比较好理解。
1. 假设一开始进行了五步A操作加入了五个数
5 4 2 3 6 5
2. 然后我们一个个输入的时候就进行单调递减队列的建立。
5
5 > 4 -> 剩余:5 4
4 > 2 -> 剩余:5 4 2
2 < 3 -> 将2移除队列,剩余:5 4 3
3,4,5 < 6 将3 4 5都移除队列,剩余:6
6 > 5 -> 剩余:6 5
现在我们就完成了单调队列的创建,现在 6 是倒数第二位(L >= 2)以后的最大值,5 是倒数第一位(L = 1)的最大值,但是我们怎么让L >= 2的时候就能查询到 6 这个数?
这个也好解决!用一个结构体就完事啦!
typedef struct
{
int num, data;
}Node;
我们初始化的时候就每个数字的num设置为1,当我们在某个数要出列的时候,我们就在新入队的那个数字的 num(new) += 旧的数字的num,此时它就是从它开始往后面共num个数字的最大值。
我们要找倒数第L个数的最大值,那么我们就从后往前的每个数字的num值加起来,直到那个值大于或者等于L的时候我们就找到了倒数第L数间的最大值。
然后我们就做完这道题啦!看不懂?没事!我们再来模拟模拟刚才的例子就懂了!
5 4 2 3 6 5
5(num = 1)
5 > 4 -> 剩余:5(1) 4(1)
4 > 2 -> 剩余:5(1) 4(1) 2(1)
2 < 3 -> 将2移除队列,3(1 + 1) = 3(2)剩余:5(1) 4(1) 3(2)
3,4,5 < 6 将3 4 5都移除队列,6(1 + 1 + 1 + 2) = 6(5)剩余:6(1)
6 > 5 -> 剩余:6(5) 5(1)
Q查询 L = 2 -> 目前NUM = 0, 第一步加上数字 5 的num, NUM = 1 < L,比L还小,所以我们加上第二步的num,NUM = 6 > L,所以我们这时候就可以输出 6 ,它就是L = 2的最大值。
5 4 2 3 6 5
↑L = 2
Q查询 L = 6:
5 4 2 3 6 5
↑L = 6
这个时候的最大值也是 6 。(L >= 2 最大值均为 6 )
那我们就来看全部代码吧!
#include <iostream>
#include <vector>
using namespace std;
const int N = 1e6 + 50;
int m, d;
typedef struct
{
int num, data;
}Node;
int main()
{
vector<Node> v;
cin >> m >> d;
int t = 0;
for(int i = 0; i < m; i++)
{
Node k; char x;
cin >> x >> k.data;
if(x == 'A')
{
k.data = (k.data + t) % d;
k.num = 1;
while(v.size() && v.back().data < k.data)
{
k.num += v.back().num;
v.pop_back();
}
v.push_back(k);
}
else if(x == 'Q')
{
int nownum = 0, j = 0;
while(k.data > nownum)
{
j++;
0 nownum += v[v.size() - j].num;
}
cout << v[v.size() - j].data << endl;
t = v[v.size() - j].data;
}
}
return 0;
}