整体二分
# 整体二分
对于多组询问,我们发现每次二分的过程都差不多是相同的,那么我们可以把询问序列一起进行二分
每次二分的时候,把 的询问变成一堆递归处理,把 的询问变成一堆递归处理
例如,求给定区间第 小的时候,我们可以对值域进行二分,然后查询答案在值域 的询问会在 中处理,否则会在其他地方被递归处理
#include<bits/stdc++.h>
using namespace std;
int N,M,tot;
const int maxn=200005,INF=1<<30;
struct AS{
int x,y,z,op;
}q[maxn<<1],lq[maxn<<1],rq[maxn<<1];
int ans[maxn],c[maxn];
inline int read(){
int ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
return ret*f;
}
inline void add_x(int x,int val){
for(int i=x;i<=N;i+=i&-i)c[i]+=val;
return ;
}
inline int get(int x){
int ret=0;
for(int i=x;i;i-=i&-i)ret+=c[i];
return ret;
}
void solve(int lval,int rval,int st,int ed){ //lval rval 对于是值域 st en 对于是询问的序号 他是在值域上进行二分
if(st>ed)return ;
if(lval==rval){
for(int i=st;i<=ed;i++){
if(q[i].op>0)ans[q[i].op]=lval;
}
return ;
}
int mid=lval+rval>>1;
int lt=0,rt=0;
for(int i=st;i<=ed;i++){
if(q[i].op==0){ //把初始化看成时一次修改
if(q[i].y<=mid)add_x(q[i].x,1),lq[++lt]=q[i]; //符合左边值域的修改
else rq[++rt]=q[i]; //符合右边值域的修改
}
else {
int cnt=get(q[i].y)-get(q[i].x-1);
if(q[i].z<=cnt)lq[++lt]=q[i];
else q[i].z-=cnt,rq[++rt]=q[i]; // q[i].z-=cnt 把在 [l,mid] 的那部分减掉
}
}
for(int i=ed;i>=st;i--)
if(q[i].op==0&&q[i].y<=mid)add_x(q[i].x,-1); //清空树状数组
for(int i=1;i<=lt;i++)q[st+i-1]=lq[i];
for(int i=1;i<=rt;i++)q[st+lt+i-1]=rq[i];
solve(lval,mid,st,st+lt-1);
solve(mid+1,rval,st+lt,ed);
return ;
}
int main(){
N=read();M=read();
for(int i=1;i<=N;i++){
++tot;
q[tot].op=0;q[tot].x=i;q[tot].y=read();
}
for(int i=1;i<=M;i++){
++tot;
q[tot].op=i;q[tot].x=read(),q[tot].y=read(),q[tot].z=read();
}
solve(-INF,INF,1,tot);
for(int i=1;i<=M;i++)printf("%d\n",ans[i]);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
如果把题目改成带修改的,那么可以把一次修改看成是先减去一个数,再加上一个数
整体二分是一种高效查找区间第 小的算法
上次更新: 2024/09/14, 12:53:16