题目描述
有 个二元组 ,编号为 到 。
有一个初始为空的栈 ,向其中加入元素 时,先不断弹出栈顶元素直至栈空或栈顶元素 满足 且 ,然后再将其加入栈中。
如果一个二元组入栈后栈内只有这一个元素,则称该二元组是「成功的」。
有 个询问 ,表示若将编号在 中的二元组按编号从小到大依次入栈,会有多少个二元组是「成功的」。
询问之间相互独立。
输入格式
从文件 stack.in
中读入数据。
第一行两个正整数 。
第二行 个正整数表示 。
第三行 个正整数表示 。
接下来 行,每行两个正整数 ,表示一组询问。
输出格式
输出到文件 stack.out
中。
行,每行一个自然数表示一组询问的答案。
样例
样例输入 1复制
10 4
3 1 3 1 2 3 3 2 1 1
10 10 2 9 7 5 4 7 6 1
1 4
7 8
7 10
1 8
样例输出 1复制
3
2
2
3
样例解释 1
以第一次询问 为例。
一开始栈为 。
加入 号二元组后栈为 ,栈中只有一个元素,该二元组是「成功的」。
加入 号二元组 时,栈顶的 的 值不大于 号二元组的,因此弹栈。此时栈空, 号二元组入栈,栈为 ,该二元组是「成功的」。
加入 号二元组 ,此时栈顶元素与之 值不同, 值比它更大,因而不需要弹栈,直接将 号二元组入栈,栈为 ,栈中有多个元素,该二元组不是「成功的」。
加入 号二元组 ,此时栈顶元素 的 值比它小,弹栈。弹栈后栈顶元素 与 的 值相同,继续弹栈。此时栈空, 号二元组入栈,栈为 ,该二元组是「成功的」。
共有 个二元组是「成功的」,因而答案为 。
样例 2
见附加文件中的 stack2.in
与 stack2.ans
。
样例 3
见附加文件中的 stack3.in
与 stack3.ans
。
分类标签
题解:
#include <stdio.h>
#include <vector>
using namespace std;
const int N = 5e5 + 5;
int n, q;
int a[N], b[N];
int c[N], ans[N];
int st[N], top;
struct ques {
int r, id;
};
template <class T>
void read(T &x) {
char c = getchar();
for (; c < 48 || c > 57; c = getchar())
;
for (x = 0; c > 47 && c < 58; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
}
vector<ques> qu[N];
vector<int> e[N];
void modify(int x) {
for (; x <= n; x += x & -x) c[x]++;
}
int sum(int x) {
int res = 0;
for (; x; x -= x & -x) res += c[x];
return res;
}
int query(int x, int y) { return sum(y) - sum(x - 1); }
int main() {
freopen("stack.in", "r", stdin);
freopen("stack.out", "w", stdout);
read(n), read(q);
for (int i = 1; i <= n; i++) read(a[i]);
for (int i = 1; i <= n; i++) read(b[i]);
for (int i = 1, l, r; i <= q; i++) {
read(l), read(r);
qu[l].push_back(ques{ r, i });
}
for (int i = 1; i <= n; i++) {
while (top && (a[st[top]] == a[i] || b[st[top]] <= b[i])) top--;
if (top)
e[st[top]].push_back(i);
else
modify(i);
st[++top] = i;
}
for (int i = 1; i <= n; i++) {
for (int j = 0; j < qu[i].size(); j++) ans[qu[i][j].id] = query(i, qu[i][j].r);
for (int j = 0; j < e[i].size(); j++) modify(e[i][j]);
}
for (int i = 1; i <= q; i++) printf("%d\n", ans[i]);
return 0;
}