LG P4278 带插入区间K小值
Description
从前有$n$只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力$a_i$。跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴。这时跳蚤国王决定理性愉悦一下,查询区间$k$小值。他每次向它的随从伏特提出这样的问题: 从左往右第$x$个到第$y$个跳蚤中,$a_i$第$k$小的值是多少。
这可难不倒伏特,他在脑袋里使用函数式线段树前缀和的方法水掉了跳蚤国王的询问。
这时伏特发现有些跳蚤跳久了弹跳力会有变化,有的会增大,有的会减少。
这可难不倒伏特,他在脑袋里使用树状数组套线段树的方法水掉了跳蚤国王的询问。(orz 主席树)
这时伏特发现有些迟到的跳蚤会插入到这一行的某个位置上,他感到非常生气,因为……他不会做了。
请你帮一帮伏特吧。
快捷版题意:带插入、修改的区间k小值在线查询。
Solution
区间K小值可以用在值域上分块解决
先用序列分块找到左右端点所在的块,如果在同一个块内,用桶统计每个值出现次数和每个值域块内的数出现次数,先找到第K小在那个块内,再在块内查找,类似BSGS
如果不在一个块内,就处理两端零散块,在中间的每个块上维护每个数出现的次数和每个块内出现的次数
修改时维护每个块内的信息
插入时维护块状链表
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<queue> #include<cmath> #include<list> using namespace std; int n,B=300,L[305],R[305],bel[70005],sum[70500][305],sumblo[305][305],m,las,tot[70005],totblo[305]; char opt[3]; queue<int>q; list<int>lst[305]; inline int read(){ int w=0,f=1; char ch=0; while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();} while(ch>='0'&&ch<='9')w=(w<<1)+(w<<3)+ch-'0',ch=getchar(); return w*f; } void solve(int k,int p,int len){ list<int>::iterator it=lst[k].begin(); for(;p;p--)++it; for(;len;len--)q.push(*it),++tot[*it],++totblo[bel[*it]],++it; } int main(){ n=read(); for(int i=1;i<=70001;i++)bel[i]=(i-1)/B+1; for(int i=1;i<=300;i++)L[i]=R[i-1]+1,R[i]=i*B; for(int i=1;i<=n;i++){ int x=read()+1; lst[bel[i]].push_back(x); for(int j=bel[i];j<=300;j++)++sum[x][j],++sumblo[bel[x]][j]; } m=read(); for(;m;m--){ scanf("%s",opt); if(opt[0]=='Q'){ int l=read()^las,r=read()^las,K=read()^las; if(bel[l]==bel[r]){ solve(bel[l],l-L[bel[l]],r-l+1); for(int i=1;;i++) if(K>totblo[i])K-=totblo[i]; else{ for(int j=L[i];;j++) if(K>tot[j])K-=tot[j]; else{las=j;break;} break; } } else{ solve(bel[l],l-L[bel[l]],R[bel[l]]-l+1),solve(bel[r],0,r-L[bel[r]]+1); for(int i=1;;i++) if(K>totblo[i]+sumblo[i][bel[r]-1]-sumblo[i][bel[l]])K-=totblo[i]+sumblo[i][bel[r]-1]-sumblo[i][bel[l]]; else{ for(int j=L[i];;j++) if(K>tot[j]+sum[j][bel[r]-1]-sum[j][bel[l]])K-=tot[j]+sum[j][bel[r]-1]-sum[j][bel[l]]; else{las=j;break;} break; } } printf("%d\n",--las); while(q.size())--tot[q.front()],--totblo[bel[q.front()]],q.pop(); } else if(opt[0]=='M'){ int x=read()^las,v=(read()^las)+1,temp=0; list<int>::iterator it=lst[bel[x]].begin(); for(int i=x-L[bel[x]];i;i--)++it; temp=*it,*it=v; for(int i=bel[x];i<=300;i++)--sum[temp][i],--sumblo[bel[temp]][i],++sum[v][i],++sumblo[bel[v]][i]; } else{ int x=read()^las,v=(read()^las)+1; list<int>::iterator it=lst[bel[x]].begin(); for(int i=x-L[bel[x]];i;--i)++it; lst[bel[x]].insert(it,v); for(int i=bel[x];i<=300;i++)++sum[v][i],++sumblo[bel[v]][i]; for(int i=bel[x]+1;i<=300;i++) if(lst[i-1].size()>300){ int temp=lst[i-1].back(); --sum[temp][i-1],--sumblo[bel[temp]][i-1]; lst[i-1].pop_back(),lst[i].push_front(temp); } else break; } } return 0; }