【Luogu P8251】[NOI Online 2022 提高组] 丹钓战

链接

洛谷

题目大意

n 个二元组 (ai,bi),编号为 1n

有一个初始为空的栈 S,向其中加入元素 (ai,bi) 时,先不断弹出栈顶元素直至栈空或栈顶元素 (aj,bj) 满足 aiajbi<bj,然后再将其加入栈中。

如果一个二元组入栈后栈内只有这一个元素,则称该二元组是“成功的”。

q 个询问 [li,ri],表示若将编号在 [li,ri] 中的二元组按编号从小到大依次入栈,会有多少个二元组是“成功的”。

思路

考虑到时间范围很紧,应该是离线做法。因为是栈,所以想到用 pi 先把 [1,n] 每个二元组在栈的位置预处理出来,然后对于子区间 [l,r] 求出有多少个二元组的位置小于等于第 l 个二元组位置即可。但是若有 l+1 个二元组比第 l 个的位置前的多,那么 l+2 虽然不是“成功的”,也会误判。因此考虑并不是预处理位置,而是预处理二元组在栈中的前一个是谁。

然后对于区间求小于等于 k,考虑用主席树维护。注意:主席树维护 pi,要加 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;
}
posted @   Jayun  阅读(38)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示