P4278 带插入区间K小值 记录
peterwuyihong · · 个人记录
原来考后才是最好颓废的时候
题意:让你维护一个序列,支持区间询问第
你发现这个数据范围很小,于是你可以随意地整一个
于是还是传统艺能地块状链表,你先分块,分成
然后你每个块都记录一个排序好的结果,动态维护这个东西。
然后每次你询问一个区间的时候就二分判定一个数是否是第
判定时就把散块的数处理掉,整块的东西再用二分掏出来即可。
复杂度
#define maxn 70010
#define B 1024
int n,m;
int a[B][B*2],b[B][B*2];
int lst,l,r,x,k;
char ch[2];
int nxt[B];
const int blo=512;
int pos[maxn],L[B],R[B],tot,siz[B];
int ask(int l,int r,int k){
int p=1,q=1;
while(siz[p]<l)l-=siz[p],p=nxt[p];
while(siz[q]<r)r-=siz[q],q=nxt[q];
int tl=0,tr=70000,mid;
while(tl<=tr){
mid=(tl+tr)>>1;
int t=0;
if(p==q)rep(i,l,r)t+=a[p][i]<mid;
else{
rep(i,l,siz[p])t+=a[p][i]<mid;
rep(i,1,r)t+=a[q][i]<mid;
int pos=nxt[p];
while(pos!=q){
t+=lower_bound(b[pos]+1,b[pos]+siz[pos]+1,mid)-b[pos]-1;
pos=nxt[pos];
}
}
if(t<k)tl=mid+1;
else tr=mid-1;
}
return tr;
}
void change(int x,int y){
int p=1,k;
while(siz[p]<x)x-=siz[p],p=nxt[p];
rep(i,1,siz[p])if(b[p][i]==a[p][x]){
k=i;
break;
}
b[p][k]=a[p][x]=y;
while(k>1&&b[p][k]<b[p][k-1])swap(b[p][k],b[p][k-1]),k--;
while(k<siz[p]&&b[p][k]>b[p][k+1])swap(b[p][k],b[p][k+1]),k++;
}
void make(int x){
rep(i,1,siz[x])b[x][i]=a[x][i];
sort(b[x]+1,b[x]+siz[x]+1);
}
void insert(int x,int y){
x--;
int p=1;
while(siz[p]<x)x-=siz[p],p=nxt[p];
per(i,siz[p],x+1)a[p][i+1]=a[p][i];
siz[p]++;
a[p][x+1]=y;
b[p][siz[p]]=y;
if(siz[p]==2*blo){
nxt[++tot]=nxt[p];
nxt[p]=tot;
rep(i,1,blo)a[tot][i]=a[p][i+blo];
siz[p]=siz[tot]=blo;
make(p),make(tot);
}else{
int k=siz[p];
while(k>1&&b[p][k]<b[p][k-1])swap(b[p][k],b[p][k-1]),k--;
}
}
signed main(){
cin>>n;
tot=n>>9;
if(n&511)tot++;
rep(i,1,tot){
L[i]=R[i-1]+1;
R[i]=L[i]+blo-1;
}R[tot]=n;
rep(i,1,tot){
siz[i]=R[i]-L[i]+1;
rep(j,L[i],R[i])
cin>>a[i][j-L[i]+1],pos[j]=i;
if(i<tot)nxt[i]=i+1;
make(i);
}
cin>>m;
while(m--){
cin>>ch;
cin>>l>>r;l^=lst,r^=lst;
if(ch[0]=='Q'){
cin>>k,k^=lst;
cout<<(lst=ask(l,r,k))<<endl;
}
if(ch[0]=='M')change(l,r);
if(ch[0]=='I')insert(l,r);
}
}