时间复杂度 \(O(nlogn)\),建树、查询、修改。

区间第 \(k\) 小值。
https://www.luogu.com.cn/problem/P3834

#include <bits/stdc++.h>
using namespace std;
using LL = long long;
struct PresidentTree{
	static constexpr int N = 2e5 + 10;
	int cntNodes, root[N];
	struct node{
		int l, r;
		int cnt;
		LL sum;
	}tr[N * 4 + N * 17];
	void modify(int &u, int v, int l, int r, int x){
		u = ++ cntNodes;
		tr[u] = tr[v];
		tr[u].cnt ++ ;
		if (l == r) return;
		int mid = l + r >> 1;
		if (x <= mid) modify(tr[u].l, tr[v].l, l, mid, x);
		else modify(tr[u].r, tr[v].r, mid + 1, r, x);
	}
	int kth(int p, int q, int l, int r, int k){
		if (l == r) return l;
		int res = tr[tr[q].l].cnt - tr[tr[p].l].cnt;
		int mid = l + r >> 1;
		if (k <= res) return kth(tr[p].l, tr[q].l, l, mid, k);
		else return kth(tr[p].r, tr[q].r, mid + 1, r, k - res);
	}
};
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	int n, m;
	cin >> n >> m;
	vector<int> a(n + 1), val;
	for (int i = 1; i <= n; i++){
		cin >> a[i];
		val.push_back(a[i]);
	}
	sort(val.begin(), val.end());
	val.erase(unique(val.begin(), val.end()), val.end());
	for (int i = 1; i <= n; i ++ ){
		a[i] = lower_bound(val.begin(), val.end(), a[i]) - val.begin();
	}
	int siz = val.size();
	
	PresidentTree pt;
	for (int i = 1; i <= n; i ++ ){
		pt.modify(pt.root[i], pt.root[i - 1], 0, siz - 1, a[i]);
	}
	while (m -- ){
		int l, r, k;
		cin >> l >> r >> k;
		cout << val[pt.kth(pt.root[l - 1], pt.root[r], 0, siz - 1, k)] << "\n";
	}
	return 0;
}

区间前 k 大值之和。
E题:https://codeforces.com/gym/102770

区间内在 \([1, k]\) 范围内的元素和。
M题:https://ac.nowcoder.com/acm/contest/12548/

posted on 2022-02-27 21:22  Hamine  阅读(72)  评论(0编辑  收藏  举报