【BZOJ5319】【JSOI2018】军训列队

【题目链接】

【思路要点】

  • 显然对于一个询问,我们应该将被询问的人以及询问的位置排序后一一匹配。
  • 也就是排序后求\(\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;
}


猜你喜欢

转载自blog.csdn.net/qq_39972971/article/details/80434682