• [模板]动态区间第k小/大(树状数组套主席树


    写挂了好多次,也不太理解

    带修改的情况如果还用(权值线段树)主席树,每个点(root[i])维护前缀的某值出现次数,

    每次修改需要对此点后面所有主席树修改,共$nlogn$个

    这里用树状数组维护前缀和,平时的树状数组实际上每个点维护的是原序列$[i,i-lowbit(i)+1]$这些值,这里也让每个树状数组维护这样一个区间的信息,而不是前缀的,这样修改一个点的值只会影响$logn$棵主席树,查询也是$logn$棵主席树的信息加起来就是整个区间的信息,每次修改存下所有需要修改/查询的主席树,同步进行加减/向下跳,这样每次修改的复杂度就是$log^2 n$的

    主席树真的好慢...跑了12s,动态区间第k大还有整体二分等做法

    (我竟然连树状数组都不理解...还看了好久树状数组)

    #include<bits/stdc++.h>
    #define mid (l+r>>1)
    #define lbt(x) (x&-x)
    using namespace std;
    const int maxn=100009;
    inline int read(){
        int ret=0,fix=1;char ch;
        while(!isdigit(ch=getchar()))fix=ch=='-'?-1:fix;
        do ret=(ret<<1)+(ret<<3)+ch-'0';
        while(isdigit(ch=getchar()));
        return fix*ret;
    }
    struct qqq{
        int tp,l,r,x;
    }qu[maxn];
    int n,m,tot,cnt;
    int hsh[maxn<<1],a[maxn];
    
    struct node{
        int l,r,cnt;
    }t[maxn*250];
    int root[maxn],q[2][30];
    inline void insert(int &x,int l,int r,int pos,int val){
        if(!x)x=++tot;
        t[x].cnt+=val;
        if(l==r)return ;
        if(pos<=mid)insert(t[x].l,l,mid,pos,val);
        else insert(t[x].r,mid+1,r,pos,val);
    }
    
    inline void add(int pos,int val,int d){
        while(pos<=n){
            insert(root[pos],1,cnt,val,d);
            pos+=lbt(pos);
        }
    }
    inline int queryt(int l,int r,int k){
        if(l==r)return l;
        int ans=0;
        for(int i=1;i<=q[0][0];i++)ans-=t[t[q[0][i]].l].cnt;
        for(int i=1;i<=q[1][0];i++)ans+=t[t[q[1][i]].l].cnt;
        if(ans>=k){
            for(int i=1;i<=q[0][0];i++)q[0][i]=t[q[0][i]].l;
            for(int i=1;i<=q[1][0];i++)q[1][i]=t[q[1][i]].l;
            return queryt(l,mid,k);
        }
        else{
            for(int i=1;i<=q[0][0];i++)q[0][i]=t[q[0][i]].r;
            for(int i=1;i<=q[1][0];i++)q[1][i]=t[q[1][i]].r;
            return queryt(mid+1,r,k-ans);
        }
    }
    inline int query(int l,int r,int k){
        l--;
        q[0][0]=q[1][0]=0;
        while(l){
            q[0][++q[0][0]]=root[l];
            l-=lbt(l);
        }
        while(r){
            q[1][++q[1][0]]=root[r];
            r-=lbt(r);
        }
        return queryt(1,cnt,k);
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)a[i]=read(),hsh[++cnt]=a[i];
        char op;
        for(int i=1;i<=m;i++){
            op=getchar();
            while(op!='C' &&op!='Q')op=getchar();
            if(op=='Q'){
                qu[i].l=read(),qu[i].r=read(),qu[i].x=read();
            }
            else if(op=='C'){
                qu[i].tp=1;
                qu[i].l=read(),qu[i].x=read();
                hsh[++cnt]=qu[i].x;
            }
        }
        sort(hsh+1,hsh+1+cnt);
        cnt=unique(hsh+1,hsh+1+cnt)-hsh-1;
        for(int i=1;i<=n;i++)a[i]=lower_bound(hsh+1,hsh+1+cnt,a[i])-hsh;
        for(int i=1;i<=m;i++)
        if(qu[i].tp)qu[i].x=lower_bound(hsh+1,hsh+1+cnt,qu[i].x)-hsh;
        
        for(int i=1;i<=n;i++)add(i,a[i],1);//建树 
        
        for(int i=1;i<=m;i++){
            if(qu[i].tp){
                add(qu[i].l,a[qu[i].l],-1);
                add(qu[i].l,qu[i].x,1);
                a[qu[i].l]=qu[i].x;
            }
            else{
                printf("%d
    ",hsh[query(qu[i].l,qu[i].r,qu[i].x)]);
            }
        }
    }
  • 相关阅读:
    不准再问我:最近过的怎么样
    嫌疑人X的献身
    关于生活
    怎么可以这样
    在WPF中动态使用图片和按钮
    MFC 中获取对话框中控件焦点的方法
    MessageBox的常见用法
    拖拽(待完善版)
    Baidu Suggestion 百度搜索(仅功能实现,烂版)
    如何判断一个对象是Element?
  • 原文地址:https://www.cnblogs.com/superminivan/p/11569505.html
Copyright © 2020-2023  润新知