【题目链接】
【思路要点】
- 显然对于一个询问,我们应该将被询问的人以及询问的位置排序后一一匹配。
- 也就是排序后求\(\sum_{i=1}^{N}|A_i-B_i|\)。
- 由于人的位置互不相同,所以\(A\)数组是递增的,而\(B\)数组是连续的一段整数,因此\(A_i\)与\(B_i\)的大小关系只有可能由小于到大于变化一次。
- 对原序列建立主席树,询问时在对应区间上二分出大小关系变化的位置,前后用区间和计算答案即可。
- 时间复杂度\(O(NLogN+MLogN)\)。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 5e5 + 5; const int MAXP = 1.5e7 + 5; template <typename T> void read(T &x) { x = 0; int f = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -f; for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0'; x *= f; } struct SegmentTree { struct Node { int lc, rc, cnt; long long sum; } a[MAXP]; int size, n; void init(int x) { n = x; size = 0; } void update(int root) { a[root].cnt = a[root].sum = 0; if (a[root].lc) { a[root].cnt += a[a[root].lc].cnt; a[root].sum += a[a[root].lc].sum; } if (a[root].rc) { a[root].cnt += a[a[root].rc].cnt; a[root].sum += a[a[root].rc].sum; } } int extend(int root, int l, int r, int val) { int ans = 0; a[ans = ++size] = a[root]; if (l == r) { a[ans].cnt += 1; a[ans].sum += val; return ans; } int mid = (l + r) / 2; if (mid >= val) a[ans].lc = extend(a[root].lc, l, mid, val); else a[ans].rc = extend(a[root].rc, mid + 1, r, val); update(ans); return ans; } int extend(int root, int val) { return extend(root, 1, n, val); } long long calc(int k, int cnt) { return (k + k + cnt - 1ll) * cnt / 2; } long long query(int rtl, int rtr, int l, int r, int k) { int cnt = a[rtr].cnt - a[rtl].cnt; long long sum = a[rtr].sum - a[rtl].sum; if (cnt == 0) return 0; if (l >= k) return sum - calc(k, cnt); if (r <= k + cnt - 1) return calc(k, cnt) - sum; int mid = (l + r) / 2; int tmp = a[a[rtr].lc].cnt - a[a[rtl].lc].cnt; return query(a[rtl].lc, a[rtr].lc, l, mid, k) + query(a[rtl].rc, a[rtr].rc, mid + 1, r, k + tmp); } long long query(int rtl, int rtr, int k) { return query(rtl, rtr, 1, n, k); } } ST; int root[MAXN], val[MAXN]; int main() { ST.init(1e6); int n, q; read(n), read(q); for (int i = 1; i <= n; i++) read(val[i]), root[i] = ST.extend(root[i - 1], val[i]); for (int i = 1; i <= q; i++) { int l, r, k; read(l), read(r), read(k); printf("%lld\n", ST.query(root[l - 1], root[r], k)); } return 0; }