整体二分——上

题目1

P3834 【模板】可持久化线段树 2 - 洛谷

java 复制代码
// 区间内第k小,第一种写法,java版
// 给定一个长度为n的数组,接下来有m条查询,格式如下
// 查询 l r k : 打印[l..r]范围内第k小的值
// 1 <= n、m <= 2 * 10^5
// 1 <= 数组中的数字 <= 10^9
// 测试链接 : https://www.luogu.com.cn/problem/P3834
// 本题是讲解157,可持久化线段树模版题,现在作为整体二分的模版题
// 提交以下的code,提交时请把类名改成"Main",可以通过所有测试用例

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Arrays;

public class Code01_RangeKth1 {

	public static int MAXN = 200001;
	public static int n, m;

	// 位置i,数值v
	public static int[][] arr = new int[MAXN][2];

	// 查询
	public static int[] qid = new int[MAXN];
	public static int[] l = new int[MAXN];
	public static int[] r = new int[MAXN];
	public static int[] k = new int[MAXN];

	// 树状数组
	public static int[] tree = new int[MAXN];

	// 整体二分
	public static int[] lset = new int[MAXN];
	public static int[] rset = new int[MAXN];

	// 查询的答案
	public static int[] ans = new int[MAXN];

	// 树状数组中的lowbit
	public static int lowbit(int i) {
		return i & -i;
	}

	// 树状数组中增加i位置的词频
	public static void add(int i, int v) {
		while (i <= n) {
			tree[i] += v;
			i += lowbit(i);
		}
	}

	// 树状数组中查询[1~i]范围的词频累加和
	public static int sum(int i) {
		int ret = 0;
		while (i > 0) {
			ret += tree[i];
			i -= lowbit(i);
		}
		return ret;
	}

	// 树状数组中查询[l~r]范围的词频累加和
	public static int query(int l, int r) {
		return sum(r) - sum(l - 1);
	}

	// 整体二分的第一种写法
	// 问题范围[ql..qr],答案范围[vl..vr],答案范围的每个下标都是数字的排名
	public static void compute(int ql, int qr, int vl, int vr) {
		if (ql > qr) {
			return;
		}
		if (vl == vr) {
			for (int i = ql; i <= qr; i++) {
				ans[qid[i]] = arr[vl][1];
			}
		} else {
			// 修改数据状况
			int mid = (vl + vr) / 2;
			for (int i = vl; i <= mid; i++) {
				add(arr[i][0], 1);
			}
			// 检查每个问题并划分左右
			int lsiz = 0, rsiz = 0;
			for (int i = ql; i <= qr; i++) {
				int id = qid[i];
				int satisfy = query(l[id], r[id]);
				if (satisfy >= k[id]) {
					lset[++lsiz] = id;
				} else {
					k[id] -= satisfy;
					rset[++rsiz] = id;
				}
			}
			for (int i = 1; i <= lsiz; i++) {
				qid[ql + i - 1] = lset[i];
			}
			for (int i = 1; i <= rsiz; i++) {
				qid[ql + lsiz + i - 1] = rset[i];
			}
			// 撤回数据状况
			for (int i = vl; i <= mid; i++) {
				add(arr[i][0], -1);
			}
			// 左右两侧各自递归
			compute(ql, ql + lsiz - 1, vl, mid);
			compute(ql + lsiz, qr, mid + 1, vr);
		}
	}

	public static void main(String[] args) throws Exception {
		FastReader in = new FastReader(System.in);
		PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
		n = in.nextInt();
		m = in.nextInt();
		for (int i = 1; i <= n; i++) {
			arr[i][0] = i;
			arr[i][1] = in.nextInt();
		}
		for (int i = 1; i <= m; i++) {
			qid[i] = i;
			l[i] = in.nextInt();
			r[i] = in.nextInt();
			k[i] = in.nextInt();
		}
		Arrays.sort(arr, 1, n + 1, (a, b) -> a[1] - b[1]);
		compute(1, m, 1, n);
		for (int i = 1; i <= m; i++) {
			out.println(ans[i]);
		}
		out.flush();
		out.close();
	}
相关推荐
Ulyanov32 分钟前
Python实现6-DOF刚体仿真器(下)——环境扰动与控制闭环
开发语言·python·算法·系统仿真·雷达电子对抗·导引头
牧以南歌〆1 小时前
数据结构<八>链式队列
c语言·数据结构·算法
Reart1 小时前
Leetcode 188.买卖股票的最佳时机4(718)
后端·算法
2601_950760791 小时前
BCMA:急性髓系白血病免疫治疗的新型可行靶点
人工智能·算法·蛋白
Reart1 小时前
Leetcode 123.买卖股票的最佳时期3(内有随心谈,718)
后端·算法
可编程芯片开发2 小时前
基于RMDCFT算法的天基雷达空间机动目标检测方法MATLAB仿真,对比FRFT和DFT算法
算法
noipp2 小时前
推荐题目:洛谷 B2099 矩阵交换行
线性代数·算法·矩阵
五条凪4 小时前
简单理解 BM25 与 TF-IDF
人工智能·算法·搜索引擎·全文检索·tf-idf
行者全栈架构师4 小时前
【码动四季】Spring Boot 可观测性体系:Micrometer + OpenTelemetry + Grafana 全链路搭建
java·算法·架构
TCW11214 小时前
AI底层系列:用C++实现线性代数的公式推导与算法设计-8.线性变化(3)
c++·人工智能·算法