动态求区间第k小,整体二分蛤不清be(菜哭.jpg ,给Qt的板子注释了一蛤
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 5e4 + 7;
const int M = 1e5 + 7;
const int INF = 1 << 30;
struct Quiry
{
int x,y,z,id,tp;
}Q[ N + M ],q1[ N + M ],q2[ N + M ];
int n,m,cnt,a[N],ans[N],x,y,z,idx;
struct Bit
{
int T[N];
int n;
inline void init(int c){n=c;memset(T, 0, sizeof(T));}
inline void add(int x,int y){for(;x<=n;x+=x&-x)T[x] += y;}
inline int sum(int u)
{
int ans = 0;
for(;u;u-=u&-u)ans += T[u];
return ans;
}
}BIT;
inline void solve(int l,int r,int AL,int AR)
{ //l,r这段操作和询问的区间,二分答案AL,AR
if(l>r)return;
if(AL==AR) //这段区间的询问的答案就是AL
{
for(int i=l;i<=r;++i)
if(Q[i].tp==2) ans[Q[i].id] = AL;
return;
}
int AM = (AL + AR) >> 1;
int p1=0,p2=0;
for(int i=l;i<=r;++i)
{
if(Q[i].tp==1) //种类1是添加值
{
if(Q[i].x<=AM) //要加的值小于二分值
{
BIT.add(Q[i].id,Q[i].y);//y就是+1还是-1
q1[++p1] = Q[i]; //有贡献的记录下来
}
else q2[++p2] = Q[i]; //没贡献的记录下来
}
else
{ //对于当前这个询问,在x到y的区间有多少比二分的答案小的
int del = BIT.sum(Q[i].y) - BIT.sum(Q[i].x-1);
if(del >= Q[i].z)q1[++p1] = Q[i]; //如果超出了询问的k
else //用q1记录下来
{
Q[i].z -= del;//否则就把那个k减掉当前贡献del
q2[++p2] = Q[i];//丢进q2
}
}
}
for(int i=1;i<=p1;++i)//q1中那些添加值有贡献的全部减掉
if(q1[i].tp==1)BIT.add(q1[i].id,-q1[i].y);
//q1数组放到前面,q2数组放到后面
for(int i=1;i<=p1;++i)Q[i+l-1] = q1[i];
for(int i=1;i<=p2;++i)Q[i+p1+l-1] = q2[i];
//先处理前半部分,再处理后半部分
solve(l,l+p1-1,AL,AM);//前半部分是对后面可能有贡献修改和已经超过k的询问
solve(l+p1,r,AM+1,AR);//后半部分是对l,r区间都没修改而且
//这两个区间互不影响,但每个区间中的是按照时间顺序来的
}
int main()
{
int T;
scanf("%d\n",&T);
while(T--)
{
scanf("%d%d\n",&n,&m);
cnt = idx = 0;
for(int i=1;i<=n;++i)
{
scanf("%d",a+i); // tp 种类1
Q[++cnt] = (Quiry){a[i],1,0,i,1};//x要加的值,y1添加,z0
} //id i位置,
for(int i=1;i<=m;++i)
{
char opt[2];
scanf("%s%d%d",opt,&x,&y);
if(*opt=='Q')
{
scanf("%d\n",&z); //x到y区间第z小
++idx; //idx询问,种类2
Q[++cnt] = (Quiry){x,y,z,idx,2};
}
else
{
Q[++cnt] = (Quiry){a[x],-1,0,x,1};//id x位置 tp种类1
a[x]=y; //x a[x],y-1删除,z 0
Q[++cnt] = (Quiry){a[x],1,0,x,1};
}
}
BIT.init(n);
solve(1,cnt,-INF,INF);
for(int i=1;i<=idx;++i)printf("%d\n",ans[i]);
}
return 0;
}