二维数点问题 1
二维数点问题
例题 1
给定一个长为 nnn 的序列 aaa,有 mmm 次询问,每次询问给定 l,r,xl,r,xl,r,x,求 [l,r][l,r][l,r] 区间中小于等于 xxx 的数的个数。
数据范围:1≤n,m,ai,l,r,x≤2×1061 \le n,m,a_i,l,r,x\le 2\times 10^61≤n,m,ai,l,r,x≤2×106。
题解
我们需要求出 l≤i≤rl\le i\le rl≤i≤r 中,有多少个数小于等于 xxx,这里有 两个偏序关系 ≤\le≤,≥\ge≥。
将两个偏序关系减少至一个,就变成求出 i≤ri\le ri≤r 有多少个数小于等于 xxx、求出 i≤l−1i\le l-1i≤l−1 有多少个数小于等于 xxx。
将二者求出来的结果 作差 就得到了原需求。
所以目标转化为实现 i≤ki\le ki≤k 有多少个数小于等于 xxx。
我们将所有的询问都转为形如 (pos,x)(pos,x)(pos,x) 的二元组,并将其按 pospospos 排序。
从 1∼n1\sim n1∼n 开始遍历原序列,并维护一个权值树状数组,对于 a[i]a[i]a[i],单点插入树状数组中即可。
然后求 i≤posi\le posi≤pos 有多少个数小于等于 xxx,就可以查询此时树状数组的 1∼x1\sim x1∼x 的前缀和。
现在我们求出了每一对二元组 (pos,x)(pos,x)(pos,x) 对应的答案,但是如何重组为 (l,r,x)(l,r,x)(l,r,x) 对应的答案呢?
有些题目可能会卡常,所以不能用 mapmapmap。
可以考虑一个结构体 nodenodenode
struct node {int pos;int x;int id;int op;
};
nodenodenode 结构体是用来存放每一个询问的信息,其中的 ididid 表示是第几次询问,其中 opopop 表示符号。
因为一次询问 (l,r,x)(l,r,x)(l,r,x) 会被拆分为两个二元组 (l−1,x)(l-1,x)(l−1,x),(r,x)(r,x)(r,x)。
我们令 (l−1,x)(l-1,x)(l−1,x) 的 opopop 为 −1-1−1,这样我们就可以将 (l−1,x)(l-1,x)(l−1,x) 的结果乘上 opopop 累加到其对应的 ans[id]ans[id]ans[id] 中,表示减去,同理对于 (r,x)(r,x)(r,x) 其 opopop 为 111,表示加上。
#include <bits/stdc++.h>
using namespace std;
//#pragma GCC optimize(2)
#define int long long
#define endl '\n'
#define PII pair<int,int>
#define INF 1e18
const int N = 2e6;template<typename T>// 单点修改和区间查询的树状数组
struct Fenwick {vector <T> tree;int n;Fenwick(int _n) : n(_n), tree(_n + 2){}// 求 1~x 的前缀和T getsum(int x) {T ans = 0;int L = x;while (x) {ans += tree[x];x = x - lowbit(x);}return ans;}// 区间查询T get_range_sum(int l, int r) {return getsum(r) - getsum(l - 1);}// 单点修改void add(int x, T k) {while (x <= n) {tree[x] += k;x += lowbit(x);}}static inline int lowbit(int x) {return x & (-x);}
};struct node {int pos;int x;int id;int op;
};void slove () {int n, m;cin >> n >> m;vector <int> a (n + 1);for (int i = 1; i <= n; i++) cin >> a[i];vector <node> q;for (int i = 1; i <= m; i++) {int l, r, x;cin >> l >> r >> x;q.emplace_back(node{l - 1, x, i, -1});q.emplace_back(node{r, x, i, 1});}sort(q.begin(), q.end(), [](node A, node B) {return A.pos < B.pos;});Fenwick<int> tree(N);vector <int> ans(m + 1, 0);int L = 1, R = 0;while (R < q.size()) {auto now = q[R];while (L <= n && L <= now.pos) {tree.add(a[L], 1);L ++;}ans[now.id] += now.op * tree.get_range_sum(1, now.x);R ++;}for (int i = 1; i <= m; i ++) {cout << ans[i] << endl;}
}signed main () {ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);slove();
}