zoukankan      html  css  js  c++  java
  • LG P4278 带插入区间K小值

    Description

    从前有$n$只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力$a_i$。跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴。这时跳蚤国王决定理性愉悦一下,查询区间$k$小值。他每次向它的随从伏特提出这样的问题: 从左往右第$x$个到第$y$个跳蚤中,$a_i$第$k$小的值是多少。
    这可难不倒伏特,他在脑袋里使用函数式线段树前缀和的方法水掉了跳蚤国王的询问。
    这时伏特发现有些跳蚤跳久了弹跳力会有变化,有的会增大,有的会减少。
    这可难不倒伏特,他在脑袋里使用树状数组套线段树的方法水掉了跳蚤国王的询问。(orz 主席树)
    这时伏特发现有些迟到的跳蚤会插入到这一行的某个位置上,他感到非常生气,因为……他不会做了。
    请你帮一帮伏特吧。
    快捷版题意:带插入、修改的区间k小值在线查询。

    Solution

    区间K小值可以用在值域上分块解决

    先用序列分块找到左右端点所在的块,如果在同一个块内,用桶统计每个值出现次数和每个值域块内的数出现次数,先找到第K小在那个块内,再在块内查找,类似BSGS

    如果不在一个块内,就处理两端零散块,在中间的每个块上维护每个数出现的次数和每个块内出现的次数

    修改时维护每个块内的信息

    插入时维护块状链表

    #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
    ",--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;
    }
    带插入区间K小值
  • 相关阅读:
    vs2012下如何调试带输入参数的程序
    BASH-数据流重导向
    VS在连接期间的一个错误的处理:转换到 COFF 期间失败: 文件无效或损坏
    vmware中NAT配置不能上网的一个解决方案
    linux下查找
    系统及用户的bash环境配置 学习笔记
    linux中控制台字体和背景颜色配置
    bash中变量的巧用
    vi 常用指令存档
    vim指令示意图
  • 原文地址:https://www.cnblogs.com/JDFZ-ZZ/p/14393644.html
Copyright © 2011-2022 走看看