[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);    }}
阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 四字成语反义词一对一 用什么成语 有难度的成语 什么用成语 有可的成语 没有办法的成语 什么能可什么成语 什么过什么过成语 求婚戒指是一个还是买一对 一对银戒指多少钱 银戒指多少钱一对 一对铂金戒指价格 白金情侣戒指多少钱一对 一对金戒指要多少钱 铂金对戒指 求婚戒指要买一对吗 天生一对戒指 情侣银戒指多少钱一对 钨金戒指对人有害吗 一对纯银戒指多少钱 求婚戒指是一个还是一对 一对铂金戒指大概多少钱 一对金戒指多少钱 一对铂金戒指多少钱 一对戒指 一对金戒指大概多少钱 炫舞戒指透明图一对 铂金戒指多少钱一对 订婚戒指要买一对吗 打一对银戒指多少钱 一对银戒指一般多少钱 戴戒指的说法 银钻戒指 2019夏季赛赛程对战表 网扣 rpap5对接焊铝塑管 对撞机 大型强子对撞机 电子对撞机 对撞机对撞一瞬间就是几亿年 儿童对数视力表