【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;
}

posted @ 2022-04-10 13:30  Jayun  阅读(35)  评论(0编辑  收藏  举报