整体二分 分析总结
晚上学了一下整体二分(没错我连整体二分都不会qwq
其实思想很简单 和 c d q cdq cdq 分治的代码实现很像 而且会用于很多更难的算法上 比如保序回归
主要收获是看到了一个大佬的代码 我才意识到之前我做分治的题最麻烦的就是递归传递数组了
每次我都要给原数组按照某种顺序排序 然后传到下一层 合并的时候还要回复原数组
其实!!!!可以直接用 v e c t o r vector vector 传 (呜呜呜我之前怎么不知道
P2617 Dynamic Rankings
给定一个含有 n n n 个数的序列 a 1 , a 2 … a n a_1,a_2 \dots a_n a1,a2…an,需要支持两种操作:
Q l r k
表示查询下标在区间 [ l , r ] [l,r] [l,r] 中的第 k k k 小的数C x y
表示将 a x a_x ax 改为 y y y
题意是让你求区间第 k k k 小 可以单点修改
考虑指定序列 只有一个查询 那就可以二分答案
判断权值在 [ l , m i d ] [l,mid] [l,mid] 的数中在询问区间的个数 如果 > k >k >k 那么答案就在 [ l , m i d ] [l,mid] [l,mid] 中 否则在 [ m i d + 1 , r ] [mid+1,r] [mid+1,r] 中
那么是否可以多个询问一起做呢
一开始的时候 有 q q q 个询问 答案区间为 [ l , r ] [l,r] [l,r]
我们把权值在 [ l , m i d ] [l,mid] [l,mid] 的数加入到下标的树状数组中 这样就可以快速询问对应区间的权值在 [ l , m i d ] [l,mid] [l,mid] 的个数
那么 q q q 个询问就可以分为答案在 [ l , m i d ] [l,mid] [l,mid] 的和答案在 [ m i d + 1 , r ] [mid+1,r] [mid+1,r] 的
然后递归分开处理两部分询问
修改就把修改操作改成两个操作 删除一个数 加上一个数
把这些操作和询问操作加在一起整体二分 分治时按顺序进行操作
删除一个数和加上一个数在分类的时候 按照这个数的权值 分到所属权值区间
最后当 l = r l=r l=r 时 这就是询问序列的答案
#include <bits/stdc++.h>
#define mid ((l+r)>>1)
#define N 200005
#define lowb(x) (x&(-x))
using namespace std;
struct node{ int ty,x,y,k,pos,rnk; };
node b[N];
vector<node> cc;
bool cmp_x(node aa,node bb){ return aa.x<bb.x; }
int n,m,num;
int a[N],pos[N],ans[N],t[N];
void add(int pos,int val){ while(pos<=n){ t[pos]+=val; pos+=lowb(pos); } }
int query(int pos){ int res=0; while(pos){ res+=t[pos]; pos-=lowb(pos); } return res; }
void work(int l,int r,vector<node> &q){
vector<node> FIR,SEC;
node u,v; int cnt=cnt=q.size(),nn;
if(l==r){
for(int i=0;i<cnt;i++) u=q[i],ans[u.rnk]=l;
return;
}
u.x=l; v.x=mid;
int x=lower_bound(b+1,b+1+n,u,cmp_x)-b,y=upper_bound(b+1,b+1+n,v,cmp_x)-b;
y=min(n,y);
if(b[y].x>mid)y--;
for(int i=x;i<=y;i++){ add(b[i].pos,1); }
for(int i=0;i<cnt;i++){
u=q[i];
if(u.ty==0)
if(u.x<=mid) add(u.pos,-1),FIR.push_back(u);
else SEC.push_back(u);
else if(u.ty==1)
if(u.x<=mid) add(u.pos,1),FIR.push_back(u);
else SEC.push_back(u);
else{
nn=query(u.y)-query(u.x-1);
if(nn>=u.k)FIR.push_back(u); else u.k-=nn,SEC.push_back(u);
}
}
for(int i=x;i<=y;i++) add(b[i].pos,-1);
for(int i=0;i<cnt;i++){
u=q[i];
if(u.ty==0&&u.x<=mid)add(u.pos,1);
if(u.ty==1&&u.x<=mid)add(u.pos,-1);
}
if(!FIR.empty()) work(l,mid,FIR);
if(!SEC.empty()) work(mid+1,r,SEC);
}
int main(){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++){ scanf("%d",&a[i]); b[i].x=a[i]; b[i].pos=i; }
sort(b+1,b+1+n,cmp_x);
char s[10]; node u;
for(int i=1;i<=m;i++){
scanf("%s",s);
if(s[0]=='Q'){ u.ty=2; scanf("%d %d %d",&u.x,&u.y,&u.k); u.rnk=++num; cc.push_back(u); }
else{
u.ty=0; scanf("%d",&u.pos); u.x=a[u.pos]; u.rnk=0; cc.push_back(u);
u.ty=1; scanf("%d",&u.x); cc.push_back(u);
a[u.pos]=u.x;
}
}
work(0,1e9,cc);
for(int i=1;i<=num;i++)printf("%d\n",ans[i]);
}