数据结构
题目描述
创建一种结构,完成下列五种功能:
I x 在当前位置插入 x 元素;
D 删除当前位置的元素;
L 将当前位置左移一位,除非它已经是第一个元素;
R 将当前位置右移一位,除非它已经是最后一个元素;
Q k 在当前位置之前,找到一个最大的 Si(1≤i≤k,Si=a1+a2+…+ai)
代码实现
#include <iostream>
#include <string>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <cstdlib>
#include <cinttypes>
#include <stack>
using namespace std;
class NewStruct{
public:
NewStruct() {
sum[0] = 0;
ans[0] = INT64_MIN;
}
void insert(long long x);
void del();
void move_left();
void move_right();
long long query(long long k);
private:
stack<long long> s1, s2;
long long sum[1005];
long long ans[1005];
};
void NewStruct::insert(long long x) {
s1.push(x);
int ind = s1.size();
sum[ind]= x + sum[ind - 1];
ans[ind] = max(ans[ind - 1], sum[ind]);
return ;
}
void NewStruct::del() {
if (s1.empty()) return ;
s1.pop();
return ;
}
void NewStruct::move_left(){
if (s1.empty()) return;
s2.push(s1.top());
del();
return ;
}
void NewStruct::move_right(){
if (s2.empty()) return ;
insert(s2.top());
s2.pop();
return ;
}
long long NewStruct::query(long long k) {
return ans[k];
}
int main() {
long long n;
cin >> n;
string op;
long long val;
NewStruct s;
for (int i = 0; i < n; i++) {
cin >> op;
switch(op[0]) {
case 'I': {
cin >> val;
s.insert(val);
} break;
case 'D': {
s.del();
} break;
case 'L': {
s.move_left();
}break;
case 'R': {
s.move_right();
} break;
case 'Q': {
cin >> val;
cout << s.query(val) << endl;
} break;
}
}
return 0;
}
单调队列
题目描述
给出一个长度为 N 的数组,一个长为 K 的滑动窗口从最左移动到最右,每次窗口移动,如下图
- 本质问题是:固定查询结尾的 RMQ 问题,例如 R M Q ( x , 7 ) RMQ(x, 7) RMQ(x,7)
- 问题性质:维护滑动窗口最值问题
- 入队:将队尾违反单调性的元素淘汰出局,再将当前元素入队
- 出队:如果队首元素超出了滑动窗口的范围,队首出队
- 队首元素:滑动窗口内的最值
- 均摊时间复杂度: O ( 1 ) O(1) O(1)
代码实现
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<queue>
#include<vector>
using namespace std;
#define MAX_N 300000
int q[MAX_N + 5], head = 0, tail = 0;
int val[MAX_N + 5];
int main() {
int n, k;
cin >> n >> k;
for (int i = 1; i <= n; i++) {
cin >> val[i];
}
for (int i = 1; i <= n; i++) {
while(tail - head && val[q[tail - 1]] > val[i]) --tail;
q[tail++] = i;
if (q[head] <= i - k) head++;
if (i >= k) {
i > k && cout << " ";
cout << val[q[head]];
}
}
cout << endl;
head = tail = 0;
for (int i = 1; i <= n; i++) {
while (head - tail && val[q[tail - 1]] < val[i]) --tail;
q[tail++] = i;
if (q[head] <= i - k) head += 1;
if (i >= k) {
i > k && cout << " ";
cout << val[q[head]];
}
}
cout << endl;
return 0;
}
单调栈
- 单调栈保留了单调队列的『⼊队』操作
- 单调栈依然是维护了⼀种单调性
- 问题性质:最近(⼤于/⼩于)关系
- ⼊栈之前,符合单调性的栈顶元素,就是我们要找的最近(⼤于/⼩于)关系
- 均摊时间复杂度:
O
(
1
)
O(1)
O(1)
题目描述
给定从左到右多个矩形,已知这此矩形的宽度都为 1,长度不完全相等。这些矩形相连排成一排,求在这些矩形包括的范围内能得到的面积最大的矩形,打印出该面积。所求矩形可以横跨多个矩形,但不能超出原有矩形所确定的范围。
代码实现
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include <stack>
#include<queue>
#include<vector>
using namespace std;
#define MAX_N 100000
long long s[MAX_N + 5], top;
long long h[MAX_N + 5], n;
long long l[MAX_N + 5], r[MAX_N + 5];
void read() {
scanf("%lld", &n);
for (long long i = 1; i <= n; i++) scanf("%lld", h + i);
return ;
}
long long solve() {
h[0] = h[n + 1] = -1;
top = -1;
s[++top] = 0;
for (long long i = 1; i <= n; i++) {
while(top != -1 && h[s[top]] >= h[i]) --top;
l[i] = s[top];
s[++top] = i;
}
top = -1;
s[++top] = n + 1;
for (long long i = n; i >= 1; i--) {
while(top != -1 && h[s[top]] >= h[i]) --top;
r[i] = s[top];
s[++top] = i;
}
long long ans = 0;
for (long long i = 1; i <= n; i++) {
ans = max(ans, h[i] * (r[i] - l[i] - 1));
}
return ans;
}
int main() {
read();
cout << solve() << endl;
return 0;
}