Unverified Commit 366ea448 authored by Trisolaris HD's avatar Trisolaris HD Committed by GitHub
Browse files

Update parallel-binsearch.md

parent fbc2596f
Loading
Loading
Loading
Loading
+79 −84
Original line number Diff line number Diff line
# [算法模板]整体二分

## 引子

很多题都可以用二分解决。但是如果我们对每个查询都直接二分,可能会收获一个 TLE 。这时候我们就会用到整体二分。整体二分的主体思路就是把多个查询一起解决。(所以这是一个离线算法)
在信息学竞赛中,有一部分题可以使用二分的办法来解决。但是当这种题目有多次询问且每次询问我们对每个查询都直接二分,可能会收获一个 TLE 。这时候我们就会用到整体二分。整体二分的主体思路就是把多个查询一起解决。(所以这是一个离线算法)

>所谓整体二分,需要数据结构题满足下性质:
> 可以使用整体二分解决的题目需要满足下性质:
>
> 1. 询问的答案具有可二分性
>
@@ -14,32 +12,34 @@
>
> 4. 贡献满足交换律,结合律,具有可加性
>
>5. 题目允许离线算法
> 5. 题目允许使用离线算法
>
>   ——许昊然《浅谈数据结构题几个非经典解法》

## 思路

定义$[l,r]$为答案的值域,$[L,R]$为答案的定义域。(也就是说这个答案是针对区间$[L,R]$
$[l,r]$ 为答案的值域,$[L,R]$ 为答案的定义域。(也就是说求答案时仅考虑下标在区间 $[L,R]$ 内的元素

- 我们首先把所有操作**按顺序**存入一个结构体中。然后开始分治。
- 在每一层分治中,利用数据结构(一般是树状数组)统计当前查询的答案和mid之间的关系。
- 根据查询出来的关系将所有查询分为q1和q2(小于等于mid和大于mid)
- 将q1和q2重新组成新的查询序列q,分治。
- 当$l=r$时,找到答案,记录答案返回即可。
- 我们首先把所有操作**按顺序**存入数组中,然后开始分治。
- 在每一层分治中,利用数据结构(常见的是树状数组)统计当前查询的答案和 mid 之间的关系。
- 根据查询出来的答案和 mid 间的关系(小于等于 mid 和大于 mid)将当前处理的操作序列分为 q1 和 q2 两份,并分别递归处理。
- 当 $l=r$ 时,找到答案,记录答案并返回即可。

### 代码

[例题:ZOJ2112](<https://cn.vjudge.net/problem/ZOJ-2112>)
例题:[「ZOJ2112」](http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2112)

??? " 例题参考代码 "

	```cpp
	#include<iostream>
	#include<cstdio>
	#include<algorithm>
	#include<cmath>
#define maxn (int)(7e4+1000)
#define inf (int)(1e9+1000)
using namespace std;

	const int maxn = (int)(7e4+1000);
	const int inf = (int)(1e9+1000);

	struct node{
		int val,x,y,k,pos,ty;
	}q[maxn],q1[maxn],q2[maxn];
@@ -66,15 +66,13 @@ void solve(int l,int r,int L,int R){
			}
			return;
		}
	for(int i=L;i<=R;i++){//遍历所有询问
		if(q[i].ty){//为查询操作
			int tmp=query(q[i].y)-query(q[i].x-1);//小于等于mid,在[x,y]区间内的元素个数
			if(tmp>=q[i].k){//mid过大
		for(int i=L;i<=R;i++){ // 遍历下标在 [L, R] 区间内的所有询问
			if(q[i].ty){ // 若当前处理的操作为查询操作
				int tmp=query(q[i].y)-query(q[i].x-1); //小于等于mid,且下标在[x,y]区间内的元素个数
				if(tmp>=q[i].k)//mid过大
					q1[++cnt1]=q[i];
			}
			else{
				q[i].k-=tmp;q2[++cnt2]=q[i];
			}
				else
					q[i].k-=tmp,q2[++cnt2]=q[i];
			}
			else{
				if(q[i].val<=mid){add(q[i].pos,q[i].k);q1[++cnt1]=q[i];}
@@ -103,15 +101,12 @@ void solve1(){
			}
		}
		solve(-inf,inf,1,cnt);
	for(int i=1;i<=cntans;i++){
		for(int i=1;i<=cntans;i++)
			printf("%d\n",ans[i]);
	}
}
	int main(){
		scanf("%d",&t);
	while(t--){
		solve1();
	}
		while(t--) solve1();

		return 0;
	}