ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

BZOJ3065 带插入区间K小值

2019-02-15 12:50:39  阅读:310  来源: 互联网

标签:BZOJ3065 ch return int sum tree 插入 小值 sl


题意

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

原序列长度 <= 35000

插入个数 <= 35000,修改个数 <= 70000,查询个数 <= 70000 ,0 <= 每时每刻的权值 <= 70000

分析

参照hzwer的题解。

得支持插入的树套树。由于没法旋转,所以只能选择替罪羊树。

学习了一下替罪羊树,具体参见WJMZBMR《重量平衡树和后缀平衡树在信息学奥赛中的应用》。维基百科上面有证明。

替罪羊树是一种不用旋转的平衡树,若一棵子树的左或右子树大小超过其大小55%-80%则暴力重构这棵子树,以此来维护平衡性,每个结点的期望重构次数是logn,实现可以自己脑补一下

在替罪羊树每个结点放一棵包含该子树所有结点的权值线段树,也就是平衡树套权值线段树

  1. 由于外层是平衡树,那么就能实现插入一个结点:找到它的位置,在根到其路径上所有结点的线段树中插入这个值
  2. 查询区间第K大:找到这个区间包含若干棵子树,拿出他们的根的权值线段树,一起做个二分
  3. 修改与插入类似
  4. 当外层平衡树失衡的时候重构之。

由于内存不够,我们还需要回收垃圾,即对数组的重复使用

时间复杂度

  1. 查询区间第K大:我觉得把那些节点提取出来就是一个玄学操作,复杂度?据洛谷管理员noip说是\(O(\log n)\)的,那么查第k大就是\(O(\log^2n)\)的。但是我个人感觉这不是正确的上界。
  2. 重构:由于要回收节点,所以共用节点很麻烦,能力限制使我不能写线段树合并。但是暴力重构的复杂度还是\(O(\log^2 n)\)的。

总时间复杂度\(O((n+m) \log^2 n)\),但是常数问题导致我过不了洛谷上面时限1s的题。

代码

#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
    rg T data=0,w=1;
    rg char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(isdigit(ch))
        data=data*10+ch-'0',ch=getchar();
    return data*w;
}
template<class T>il T read(rg T&x){
    return x=read<T>();
}
typedef long long ll;
using std::vector;

co int N=7e4+1,LG=1e7; // memory limit
int n,m;
// Tree Tao Tree
namespace T{
    // Interval Tree
    int tot,bin[LG];
    int L[LG],R[LG],sum[LG];
    il int construct() {return bin[0]?bin[bin[0]--]:++tot;}
    il void destruct(int&x){
        if(!x) return;
        destruct(L[x]),destruct(R[x]);
        bin[++bin[0]]=x,sum[x]=0,x=0; // edit 2: x=0
    }
    void insert(int&x,int l,int r,int p,int d){
        if(!x) x=construct();
        sum[x]+=d;
        if(!sum[x]){
            destruct(x);
            return;
        }
        if(l==r) return;
        int m=(l+r)/2;
        if(p<=m) insert(L[x],l,m,p,d);
        else insert(R[x],m+1,r,p,d);
    }
    int query(vector<int>&x,co vector<int>&vs,int l,int r,int k){
        if(l==r) return l;
        int s=0,m=(l+r)/2;
        for(rg unsigned i=0;i<x.size();++i)
            s+=sum[L[x[i]]];
        for(rg unsigned i=0;i<vs.size();++i)
            s+=(l<=vs[i]&&vs[i]<=m);
        if(s>=k){
            for(rg unsigned i=0;i<x.size();++i)
                x[i]=L[x[i]];
            return query(x,vs,l,m,k);
        }
        else{
            for(rg unsigned i=0;i<x.size();++i)
                x[i]=R[x[i]];
            return query(x,vs,m+1,r,k-s);
        }
    }
    // Scapegoat Tree
    co double ratio=0.75; // edit 3:double
    int root,pot[N];
    int val[N],tree[N],ch[N][2];
    void build(int&t,int l,int r){
        if(l>r) return;
        int m=(l+r)/2;
        t=pot[m];
        for(rg int i=l;i<=r;++i)
            insert(tree[t],0,7e4,val[pot[i]],1);
        if(l==r) return;
        build(ch[t][0],l,m-1),build(ch[t][1],m+1,r); // edit 1:m-1 for balanced tree
    }
    void split(int t,int l,int r,vector<int>&x,vector<int>&vs){
        int sl=sum[tree[ch[t][0]]],st=sum[tree[t]];
        if(l==1&&r==st){
            x.push_back(tree[t]);
            return;
        }
        if(l<=sl+1&&sl+1<=r) vs.push_back(val[t]);
        if(r<=sl) split(ch[t][0],l,r,x,vs);
        else if(l>sl+1) split(ch[t][1],l-sl-1,r-sl-1,x,vs); // edit 3: 1,not 0
        else{
            if(l<=sl) split(ch[t][0],l,sl,x,vs);
            if(r>sl+1) split(ch[t][1],1,r-sl-1,x,vs);
        }
    }
    int query(int t,int l,int r,int k){
        vector<int> x,vs;
        split(t,l,r,x,vs);
        return query(x,vs,0,7e4,k);
    }
    int modify(int t,int k,int v){
        insert(tree[t],0,7e4,v,1);
        int o,sl=sum[tree[ch[t][0]]];
        if(sl+1==k) o=val[t],val[t]=v;
        else if(sl>=k) o=modify(ch[t][0],k,v);
        else o=modify(ch[t][1],k-sl-1,v);
        insert(tree[t],0,7e4,o,-1);
        return o;
    }
    void remove(int&t){
        if(!t) return;
        remove(ch[t][0]);
        pot[++pot[0]]=t;
        remove(ch[t][1]);
        destruct(tree[t]),t=0; // edit 2:t=0
    }
    il void rebuild(int&t){
        remove(t);
        build(t,1,pot[0]);
        pot[0]=0;
    }
    int tmp;
    void insert(int&t,int k,int v){
        if(!t){
            t=++n;
            val[t]=v,insert(tree[t],0,7e4,v,1);
            return;
        }
        insert(tree[t],0,7e4,v,1);
        int sl=sum[tree[ch[t][0]]];
        if(sl>=k) insert(ch[t][0],k,v);
        else insert(ch[t][1],k-sl-1,v);
        if(sum[tree[t]]*ratio>std::max(sum[tree[ch[t][0]]],sum[tree[ch[t][1]]])){
            if(tmp){ // edit 4: when rebuilding must change ch as well
                rebuild(ch[t][tmp==ch[t][1]]);
                tmp=0;
            }
        }
        else tmp=t;
    }
}

int main(){
//  freopen("BZOJ3065.in","r",stdin);
//  freopen("BZOJ3065.out","w",stdout);
    read(n);
    for(rg int i=1;i<=n;++i)
        read(T::val[i]),T::pot[i]=i;
    T::build(T::root,1,n);
    read(m);
    int lastans=0;
    while(m--){
        char opt[2];
        scanf("%s",opt);
        switch(opt[0]){
            case 'Q':{
                int l=read<int>()^lastans,r=read<int>()^lastans,k=read<int>()^lastans;
                printf("%d\n",lastans=T::query(T::root,l,r,k));
                break;
            }
            case 'M':{
                int k=read<int>()^lastans,v=read<int>()^lastans;
                T::modify(T::root,k,v);
                break;
            }
            case 'I':{
                int k=read<int>()^lastans,v=read<int>()^lastans;
                T::insert(T::root,k-1,v);
                if(T::tmp){
                    T::rebuild(T::root);
                    T::tmp=0;
                }
                break;
            }
            default:assert(0);
        }
    }
    return 0;
}

标签:BZOJ3065,ch,return,int,sum,tree,插入,小值,sl
来源: https://www.cnblogs.com/autoint/p/10383048.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有