首页 > 其他分享 >整体二分

整体二分

时间:2024-08-06 21:39:18浏览次数:14  
标签:二分 cnt int mn 整体 mid ++ mx

学了一下,感觉不深刻。

说是整体二分,不如说是离线的归并排序。

考虑这个问题:Luogu P3834 【模板】可持久化线段树 2

\(m\) 次询问,每次询问给出 \((l,r,k)\),问 \([l,r]\) 中第 \(k\) 小的值。

我们首先先简化一下:如果 \(m=1\),怎么维护?

先二分出一个 \(x\),建立树状数组维护 \(\le x\) 的个数,判断其是否小于 \(k\) 即可。

那加入 \(m\) 次询问怎么办呢?

可以离线下来,运用分治思想将同一范围内的答案统一处理。

具体的,我们定义结构体 \((x,y,k,id,opt)\)。对于询问,\(x,y,k\) 表示查询 \([x,y]\) 的第 \(k\) 小,此时的 \(opt=1\),对于原数,\(x\) 表示原值。

定义操作函数 solve(l,r,L,R) 表示当前处理到 \([l,r]\),值域为 \([L,R]\),对于 \(L=R\),显然,\(l\sim r\) 的答案就为 \(L\)(\(R\))。

  • 对于原数,如果 \(x\le mid\),那么其在树状数组上的位置就加一。

  • 对于询问,查询 \([x,y]\) 的个数相当于查询原数的值在 \([L,mid]\) 的个数,我们令为 \(p\),如果 \(p\ge k\),那么此时答案在 \([L,mid]\) 中,否则在 \([mid+1,R]\) 中,需要注意,此时的 \(q_i\) 的 \(k\) 要减去 \(p\)。

码风有点抽象,切勿锐评 /qd。

点击查看代码
#include <bits/stdc++.h>
#define int long long

using namespace std;

const int N = 2e5 + 100;

int n, m, cnt, mn = 1e18, mx = -1e18, ans[N];

struct Node {
	int x, y, k, id, opt;
} q[N], q1[N], q2[N];

struct Bit {
	int f[N];
	int lowbit(int x) { return x & -x; }
	void add(int x, int k) { while (x <= n) { f[x] += k; x += lowbit(x); } }
	int getsum(int x) { int sum = 0; while (x) { sum += f[x]; x -= lowbit(x); } return sum; }
} bit;

void solve(int l, int r, int L, int R) {
	if (l > r) return ;
	if (L == R) { for (int i = l; i <= r; i++) { if (q[i].opt) { ans[q[i].id] = L; } } return ; }
	int mid = (L + R) >> 1, p1 = 0, p2 = 0;
	for (int i = l; i <= r; i++) { if (!q[i].opt) { if (q[i].x <= mid) { bit.add(q[i].id, 1); q1[++p1] = q[i]; } else { q2[++p2] = q[i]; } } else { int num = bit.getsum(q[i].y) - bit.getsum(q[i].x - 1); if (num >= q[i].k) { q1[++p1] = q[i]; } else { q[i].k -= num; q2[++p2] = q[i]; } } }
	for (int i = 1; i <= p1; i++) { if (!q1[i].opt) { bit.add(q1[i].id, -1); } } 
	for (int i = 1; i <= p1; i++) { q[i + l - 1] = q1[i]; }
	for (int i = 1; i <= p2; i++) { q[i + l + p1 - 1] = q2[i]; }
	solve(l, l + p1 - 1, L, mid), solve(l + p1, r, mid + 1, R);
}

signed main() {
	cin >> n >> m;
	for (int i = 1, x; i <= n; i++) { cin >> x; q[++cnt] = {x, 0, 0, i, 0}; mn = min(mn, x), mx = max(mx, x); }
	for (int i = 1, l, r, k; i <= m; i++) { cin >> l >> r >> k; q[++cnt] = {l, r, k, i, 1}; }
	solve(1, cnt, mn, mx);
	for (int i = 1; i <= m; i++) cout << ans[i] << '\n';
	return 0;
}

标签:二分,cnt,int,mn,整体,mid,++,mx
From: https://www.cnblogs.com/ydq1101/p/18346039

相关文章

  • 二分法题目合集
    1.锯齿形数组找target有一个数组,前半部分有序,后半部分也有序,前半部分的开头元素大于后半部分的结尾元素,请从这个数组中找出target。解题思路:一开始我们就可以根据target和数组结尾元素的大小关系确定target属于哪个部分,之后将target和mid比较时就能根据位于哪一部分去更新l,r。......
  • 整体二分
    整体二分一类题目可以二分解决,但是有多次询问,于是考虑整体二分,主要思想为把多个查询一起解决,是一个离线算法。使用条件:答案可以二分求得。允许离线。修改对判定答案的贡献互相独立,修改之间互相独立。修改如果对判定答案有贡献,则贡献为一与判定标准无关的定值。实现首先......
  • CF1993D-二分+dp处理中位数
    CF1993D-二分+dp处理中位数大致题意给定两个正整数n和k以及另一个由n个整数组成的数组a。在一次操作中,可以选择a的任意一个大小为k的子数组,然后将其从数组中删除,而不改变其他元素的顺序。更正式地说,假设$(l,r)$是对子数组\(a_l,a_{l+1},…,a_r\)的操作,使得\(r......
  • 【轨物方案】智慧供热物联网整体解决方案
      目前城市供暖系统当中,供暖设备一直得不到更新和升级,没有合理的监控设备,导致对供暖的合理调控不理想,供暖严重失调而浑然不知,进而出现冷热不均的问题,极易造成资源严重浪费。缺乏成熟的管理系统,导致运维困难;当供暖单位对供暖设施的维修改造不到位,造成供暖网管老化、泄漏、堵......
  • 整数二分(以数的范围例题为例)
    整数二分算法是一种在有序数组序列中查找特定元素的高效算法。‌ 它通过反复将搜索范围缩小一半来进行搜索,‌从而快速找到目标元素的位置。‌这种算法适用于处理已排序的数组,‌通过不断地将搜索区间一分为二,‌来缩小查找范围,‌直到找到目标元素或者搜索区间为空。‌整数二分算......
  • 整数二分(c++)
    1、什么是整数二分:即可以看做成找数字那个游戏在一百个数字中找到指定的数字(66)A出题B:50A50太小了B:(50+100)/2=75A75太大了B:(50+75)/2=62…所以也可以知道一个结论:有单调性,一定可以二分。可以二分的题目,不一定有单调性。2、代码思路:1、寻找到满足......
  • 算法DAY 1 二分法查找数的范围
    题目给定一个按照升序排列的长度为n的整数数组,以及q个查询。对于每个查询,返回一个元素k的起始位置和终止位置(位置从0开始计数)。如果数组中不存在该元素,则返回-1-1。输入格式第一行包含整数n和q,表示数组长度和询问个数。第二行包含n个整数(均在1~10000范围内),表示完......
  • 匈牙利算法--二分图的最大匹配
    匈牙利算法--二分图的最大匹配给定一个二分图,其中左半部包含 n1个点(编号 1∼n1),右半部包含 n2 个点(编号 1∼n2),二分图共包含 m 条边。数据保证任意一条边的两个端点都不可能在同一部分中。请你求出二分图的最大匹配数。二分图的匹配:给定一个二分图 G,在 G的一个子......
  • 二分算法思路及解题代码
    二分算法一、第一种二分(easy)例题一:力扣704.二分查找-力扣(LeetCode)方法:1.暴力循环遍历,时间复杂度为O(n),代码太简单就省略了也不建议用这种方法2.二分算法(重点)时间复杂度O(logn)解法思路:如果利用暴力那么这道题有一个很重要的条件没有用,那就是有序,如果选取......
  • 数据结构与算法-二分搜索树节点的查找
    ......