[BZOJ]3065: 带插入区间K小值 块状链表
来源:互联网 发布:linux 设置命令别名 编辑:程序博客网 时间:2024/06/07 02:46
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); }}
阅读全文