Description
从前有n只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力a[i]。跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴。这时跳蚤国王决定理性愉悦一下,查询区间k小值。他每次向它的随从伏特提出这样的问题: 从左往右第x个到第y个跳蚤中,a[i]第k小的值是多少。
这可难不倒伏特,他在脑袋里使用函数式线段树前缀和的方法水掉了跳蚤国王的询问。
这时伏特发现有些跳蚤跳久了弹跳力会有变化,有的会增大,有的会减少。
这可难不倒伏特,他在脑袋里使用树状数组套线段树的方法水掉了跳蚤国王的询问。(orz 主席树)
这时伏特发现有些迟到的跳蚤会插入到这一行的某个位置上,他感到非常生气,因为……他不会做了。
请你帮一帮伏特吧。
快捷版题意:带插入、修改的区间k小值在线查询。
题解:
分块。维护每块的原数组与排序后数组,当某块的size刚好达到两个块的大小时,分裂成两块,其它都是普通分块的套路了。如果要对拍,记得在对拍完之后加上强制在线,别问我是怎么知道的……
代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int block_size=600;
const int Maxn=70010;
const int inf=2147483647;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
int n,num,next[120],b[120][1210],a[120][1210],size[120];
//a为原数组 b为排序后数组 num为块数 next[i]为第i块的下一块序号
void rebuild(int x)//重构第x块
{
for(int i=1;i<=size[x];i++)b[x][i]=a[x][i];
sort(b[x]+1,b[x]+1+size[x]);
}
int binary(int x,int v)//第x块有多少数比v小
{
int l=1,r=size[x];
while(l<=r)
{
int mid=l+r>>1;
if(b[x][mid]<v)l=mid+1;
else r=mid-1;
}
return l-1;
}
int t1,t2;
void get(int x)//t1表示x所属块的序号 t2表示x是块中的第几个
{
t1=1;t2=x;
while(t2>=size[t1])
{
if(t2==size[t1])break;
if(next[t1]==-1)break;
t2-=size[t1];
t1=next[t1];
}
}
int query(int L,int R,int k)
{
int bl,br,tl,tr;
get(L);bl=t1;tl=t2;
get(R);br=t1;tr=t2;
int l=0,r=70000;
while(l<=r)
{
int mid=l+r>>1,tot=0;
if(bl==br)
{
for(int i=tl;i<=tr;i++)
tot+=(a[bl][i]<mid);
}
else
{
for(int i=tl;i<=size[bl];i++)tot+=(a[bl][i]<mid);
for(int i=1;i<=tr;i++)tot+=(a[br][i]<mid);
int t=next[bl];
while(t!=br)
{
tot+=binary(t,mid);
t=next[t];
}
}
if(tot<=k-1)l=mid+1;
else r=mid-1;
}
return l-1;
}
void modify(int x,int v)
{
get(x);int t=t1;x=t2;
int i;
for(i=1;i<=size[t];i++)
if(a[t][x]==b[t][i])break;
a[t][x]=b[t][i]=v;
while(i<size[t]&&b[t][i]>b[t][i+1])swap(b[t][i],b[t][i+1]),i++;
while(i>1&&b[t][i]<b[t][i-1])swap(b[t][i],b[t][i-1]),i--;
}
void insert(int x,int v)
{
get(x);int t=t1;x=t2;
for(int i=size[t]+1;i>x;i--)a[t][i]=a[t][i-1];
a[t][x]=b[t][++size[t]]=v;
if(size[t]==2*block_size)
{
next[++num]=next[t];next[t]=num;
size[t]=size[num]=block_size;
for(int i=1;i<=block_size;i++)a[num][i]=a[t][i+block_size];
rebuild(num);rebuild(t);
}
else
{
int i=size[t];
while(i>1&&b[t][i]<b[t][i-1])swap(b[t][i],b[t][i-1]),i--;
}
}
int main()
{
memset(next,-1,sizeof(next));
n=read();num=(n-1)/block_size+1;
for(int i=1;i<=n;i++)
{
int t1=(i-1)/block_size+1,t2=(i-1)%block_size+1;
a[t1][t2]=b[t1][t2]=read();
size[t1]++;
}
for(int i=1;i<=num;i++)
{
rebuild(i);
if(i!=num)next[i]=i+1;
}
int zaixian=1;
int ans=0,Q=read();
while(Q--)
{
char str[3];
scanf("%s",str);
int x=read()^(ans*zaixian),y=read()^(ans*zaixian);
if(str[0]=='Q')ans=query(x,y,read()^(ans*zaixian)),printf("%d\n",ans);
else if(str[0]=='M')modify(x,y);
else insert(x,y);
}
}