【Luogu P8251】[NOI Online 2022 提高组] 丹钓战
链接
题目大意
有 \(n\) 个二元组 \((a_i, b_i)\),编号为 \(1\) 到 \(n\)。
有一个初始为空的栈 \(S\),向其中加入元素 \((a_i, b_i)\) 时,先不断弹出栈顶元素直至栈空或栈顶元素 \((a_j,b_j)\) 满足 \(a_i \neq a_j\) 且 \(b_i < b_j\),然后再将其加入栈中。
如果一个二元组入栈后栈内只有这一个元素,则称该二元组是“成功的”。
有 \(q\) 个询问 \([l_i, r_i]\),表示若将编号在 \([l_i, r_i]\) 中的二元组按编号从小到大依次入栈,会有多少个二元组是“成功的”。
思路
考虑到时间范围很紧,应该是离线做法。因为是栈,所以想到用 \(p_i\) 先把 \([1,n]\) 每个二元组在栈的位置预处理出来,然后对于子区间 \([l,r]\) 求出有多少个二元组的位置小于等于第 \(l\) 个二元组位置即可。但是若有 \(l+1\) 个二元组比第 \(l\) 个的位置前的多,那么 \(l+2\) 虽然不是“成功的”,也会误判。因此考虑并不是预处理位置,而是预处理二元组在栈中的前一个是谁。
然后对于区间求小于等于 \(k\),考虑用主席树维护。注意:主席树维护 \(p_i\),要加 1,否则“成功的”二元组的 \(p\) 值为 0,主席树会出错。
代码:
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define stoorz_and_QuantAsk using
#define AK namespace
#define IOI_and_Jayun_is_stupid std
#define ll long long
stoorz_and_QuantAsk AK IOI_and_Jayun_is_stupid;
const int N = 5e5 + 10;
inline ll Read() {
ll x = 0, f = 1;
char c = getchar();
while (c != '-' && (c < '0' || c > '9')) c = getchar();
if (c == '-') f = -f, c = getchar();
while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
return x * f;
}
int n, q;
int a[N], b[N], st[N], top, p[N];
vector <int> v;
bool cmp (int mid, int val) {
return b[mid] > val;
}
int root[N];
struct Seg
{
int lt[N<<5], rt[N<<5], cnt;
int sum[N<<5];
void build(int &x, int l, int r)
{
x = ++cnt;
if(l == r) return;
int mid = (l + r) >> 1;
build(lt[x], l, mid);
build(rt[x], mid + 1, r);
}
int change(int x, int l, int r, int p)
{
int Newx = ++cnt; lt[Newx] = lt[x], rt[Newx] = rt[x], sum[Newx] = sum[x];
if (l == r) {sum[Newx]++; return Newx;}
int mid = (l + r) >> 1;
if(p <= mid) lt[Newx] = change(lt[Newx], l, mid, p);
else rt[Newx] = change (rt[Newx], mid + 1, r, p);
sum[Newx] = sum[lt[Newx]] + sum[rt[Newx]];
return Newx;
}
int query (int L, int R, int l, int r, int x, int y)
{
if (x <= l && r <= y) return sum[R] - sum[L];
int ans = 0, mid = (l + r) >> 1;
if(x <= mid) ans += query (lt[L], lt[R], l, mid, x, y);
if(y > mid) ans += query (rt[L], rt[R], mid + 1, r, x, y);
return ans;
}
}sgt;
int main() {
freopen("stack.in", "r", stdin);
freopen("stack.out", "w", stdout);
n = Read(), q = Read();
for (int i = 1; i <= n; i++) a[i] = Read();
for (int i = 1; i <= n; i++) b[i] = Read();
for (int i = 1; i <= n; i++) {
if (top == 0) {
p[i] = st[top++] + 1;
st[top] = i;
continue;
}
top = lower_bound(st + 1, st + 1 + top, b[i], cmp) - st - 1;
if (a[st[top]] == a[i]) top--;
p[i] = st[top++] + 1;
st[top] = i;
}
sgt.build(root[0], 1, n);
for (int i = 1; i <= n; i++)
root[i] = sgt.change(root[i - 1], 1, n, p[i]);
for (int i = 1; i <= q; i++) {
int l = Read(), r = Read();
printf ("%d\n", sgt.query(root[l - 1], root[r], 1, n, 1, p[l]));
}
return 0;
}