目录
1.Problem
Let a1,…,ana1,…,an be an array of nn positive integers. In one operation, you can choose an index ii such that ai=iai=i, and remove aiai from the array (after the removal, the remaining parts are concatenated).
The weight of aa is defined as the maximum number of elements you can remove.
You must answer qq independent queries (x,y)(x,y): after replacing the xx first elements of aa and the yy last elements of aa by n+1n+1 (making them impossible to remove), what would be the weight of aa?
2.Input
The first line contains two integers nn and qq (1≤n,q≤3⋅1051≤n,q≤3⋅105) — the length of the array and the number of queries.
The second line contains nn integers a1a1, a2a2, ..., anan (1≤ai≤n1≤ai≤n) — elements of the array.
The ii-th of the next qq lines contains two integers xx and yy (x,y≥0x,y≥0 and x+y<nx+y<n).
3.Output
Print qq lines, ii-th line should contain a single integer — the answer to the ii-th query.
4.Examples
4.1input
13 5
2 2 3 9 5 4 6 5 7 8 3 11 13
3 1
0 0
2 4
5 0
0 12
4.2output
5
11
6
1
0
5.Code
#include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
template <typename T> bool chkmax(T &x, T y) { return x < y ? x = y, true : false; }
template <typename T> bool chkmin(T &x, T y) { return x > y ? x = y, true : false; }
int readint() {
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
const int MAXN = 300005;
const int MAXQ = 1100000;
const int MAXPST = 10000005;
int n, q;
int a[MAXN], lf[MAXN];
namespace sgt {
int lazy[MAXQ], maxa[MAXQ];
void pushdown(int id) {
if (lazy[id]) {
lazy[id << 1] += lazy[id], maxa[id << 1] += lazy[id];
lazy[id << 1 | 1] += lazy[id], maxa[id << 1 | 1] += lazy[id];
lazy[id] = 0;
}
}
int find(int id, int l, int r, int ql, int qr, int c) {
if (maxa[id] < c) return l - 1;
if (l == r) return maxa[id] >= c ? l : l - 1;
pushdown(id);
int mid = (l + r) / 2;
if (qr <= mid) return find(id << 1, l, mid, ql, qr, c);
else if (ql > mid) return find(id << 1 | 1, mid + 1, r, ql, qr, c);
else if (maxa[id << 1 | 1] >= c) return find(id << 1 | 1, mid + 1, r, mid + 1, qr, c);
else return find(id << 1, l, mid, ql, mid, c);
}
void change(int id, int l, int r, int ql, int qr, int c) {
if (ql > qr) return;
if (l == ql && r == qr) return (void)(lazy[id] += c, maxa[id] += c);
pushdown(id);
int mid = (l + r) / 2;
if (qr <= mid) change(id << 1, l, mid, ql, qr, c);
else if (ql > mid) change(id << 1 | 1, mid + 1, r, ql, qr, c);
else change(id << 1, l, mid, ql, mid, c), change(id << 1 | 1, mid + 1, r, mid + 1, qr, c);
maxa[id] = max(maxa[id << 1], maxa[id << 1 | 1]);
}
}
namespace pst {
int ncnt;
int vs[MAXN], lch[MAXPST], rch[MAXPST], val[MAXPST];
void build(int id, int l, int r) {
if (l == r) return;
int mid = (l + r) / 2;
build(lch[id] = ++ncnt, l, mid);
build(rch[id] = ++ncnt, mid + 1, r);
}
int change(int id, int l, int r, int x) {
int rt = ++ncnt;
val[rt] = val[id] + 1, lch[rt] = lch[id], rch[rt] = rch[id];
if (l == r) return rt;
int mid = (l + r) / 2;
if (x <= mid) lch[rt] = change(lch[rt], l, mid, x);
else rch[rt] = change(rch[rt], mid + 1, r, x);
return rt;
}
int query(int id1, int id2, int l, int r, int ql, int qr) {
if (l == ql && r == qr) return val[id2] - val[id1];
int mid = (l + r) / 2;
if (qr <= mid) return query(lch[id1], lch[id2], l, mid, ql, qr);
else if (ql > mid) return query(rch[id1], rch[id2], mid + 1, r, ql, qr);
else return query(lch[id1], lch[id2], l, mid, ql, mid) + query(rch[id1], rch[id2], mid + 1, r, mid + 1, qr);
}
}
int main() {
n = readint(); q = readint();
for (int i = 1; i <= n; i++) a[i] = readint() - i;
for (int i = 1; i <= n; i++) {
if (a[i] > 0) lf[i] = 0;
else {
int pl = sgt::find(1, 1, n, 1, i, -a[i]);
lf[i] = pl;
sgt::change(1, 1, n, 1, pl, 1);
}
}
pst::build(pst::vs[0] = 1, 0, n);
for (int i = 1; i <= n; i++) pst::vs[i] = pst::change(pst::vs[i - 1], 0, n, lf[i]);
int x, y, l, r;
while (q--) {
x = readint(); y = readint();
l = x + 1, r = n - y;
printf("%d\n", pst::query(pst::vs[l - 1], pst::vs[r], 0, n, l, r));
}
return 0;
}
6.Conclusion
这段代码是一个C++程序,主要实现了一个复杂的数据结构,涉及到线段树(Segment Tree)和持久化线段树(Persistent Segment Tree)的概念。以下是代码的简要说明:
头文件和宏定义:包含了一些标准的C++头文件,以及一些宏定义,用于简化代码中的一些操作,如
pb
(push_back)、mp
(make_pair)等。命名空间和类型定义:使用了
std
命名空间,并定义了一些类型别名,如ll
(long long)、ull
(unsigned long long)、pii
(pair of integers)和pll
(pair of long long)等。读取整数的函数:
readint
函数用于从标准输入中读取一个整数,通过字符处理实现。全局变量和常量:定义了一些全局变量和常量,如数组
a
和lf
,以及常量MAXN
、MAXQ
和MAXPST
。命名空间sgt:实现了线段树的一些操作,包括
pushdown
(向下传递懒惰标记)、find
(查找满足条件的位置)和change
(更新区间的值)等。命名空间pst:实现了持久化线段树的一些操作,包括
build
(建树)、change
(更新节点的值)和query
(查询区间的值)等。主函数:程序的入口,首先读取输入的n和q,然后通过
readint
函数读取数组a。接着,使用线段树处理a数组,找到满足条件的位置并更新线段树。之后,建立持久化线段树。最后,通过读取查询,使用持久化线段树查询指定区间的值并输出。需要注意的是,这段代码实现了一种特定的算法或数据结构,如果要理解代码的具体逻辑和功能,需要深入了解线段树和持久化线段树的原理。