zoukankan      html  css  js  c++  java
  • 洛谷 3380 【模板】二逼平衡树(树状数组套权值线段树)

    题目描述

    您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:

    1. 查询k在区间内的排名

    2. 查询区间内排名为k的值

    3. 修改某一位值上的数值

    4. 查询k在区间内的前驱(前驱定义为严格小于x,且最大的数,若不存在输出-2147483647)

    5. 查询k在区间内的后继(后继定义为严格大于x,且最小的数,若不存在输出2147483647)

    注意上面两条要求和tyvj或者bzoj不一样,请注意

    输入输出格式

    输入格式:

    第一行两个数 n,m 表示长度为n的有序序列和m个操作

    第二行有n个数,表示有序序列

    下面有m行,opt表示操作标号

    若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间[l,r]的排名

    若opt=2 则为操作2,之后有三个数l,r,k 表示查询区间[l,r]内排名为k的数

    若opt=3 则为操作3,之后有两个数pos,k 表示将pos位置的数修改为k

    若opt=4 则为操作4,之后有三个数l,r,k 表示查询区间[l,r]内k的前驱

    若opt=5 则为操作5,之后有三个数l,r,k 表示查询区间[l,r]内k的后继

    输出格式:

    对于操作1,2,4,5各输出一行,表示查询结果

    输入输出样例

    输入样例#1:
    9 6
    4 2 2 1 9 4 0 1 1
    2 1 4 3
    3 4 10
    2 1 4 3
    1 2 5 9
    4 3 9 5
    5 2 8 5
    输出样例#1:
    2
    4
    3
    4
    9

    说明

    时空限制:2s,128M

    n,m leq 5cdot {10}^4n,m5104​​ 保证有序序列所有值在任何时刻满足 [0, {10} ^8][0,108​​]

    题目来源:bzoj3196 / Tyvj1730 二逼平衡树,在此鸣谢

    此数据为洛谷原创。(特别提醒:此数据不保证操作5、6一定存在,故请务必考虑不存在的情况)

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #define N 50001
    #define M N*400
    #define lowbit(x) x&(-x)
    #define calmid int mid=l+r>>1;
    #define preA  A[0]=0; while(r) A[++A[0]]=root[r],r-=lowbit(r);
    #define preB  B[0]=0; while(l) B[++B[0]]=root[l],l-=lowbit(l);
    #define goleftA for(int i=1;i<=A[0];i++) A[i]=lc[A[i]];  
    #define goleftB for(int i=1;i<=B[0];i++) B[i]=lc[B[i]];
    #define gorightA for(int i=1;i<=A[0];i++) A[i]=rc[A[i]]; 
    #define gorightB for(int i=1;i<=B[0];i++) B[i]=rc[B[i]]; 
    #define gotmpA     for(int i=1;i<=A[0];i++) tmp+=sum[lc[A[i]]];
    #define gotmpB     for(int i=1;i<=B[0];i++) tmp-=sum[lc[B[i]]];
    int n,m,tot;
    int root[N],a[N],hash[N<<1];
    int A[20],B[20];
    namespace CMT
    {
        int cnt=0,lc[M],rc[M],sum[M];
        void insert(int &k,int l,int r,int pos,int w)
        {
            if(!k) k=++cnt;
            sum[k]+=w;
            if(l==r) return;
            int mid=l+r>>1;
            if(pos<=mid) insert(lc[k],l,mid,pos,w);
            else insert(rc[k],mid+1,r,pos,w);
        }
        int getrank(int l,int r,int w,bool ty)
        {
            int tmp=0;
            if(l==r) 
            {
                if(!ty) return 0;
                else 
                {
                    for(int i=1;i<=A[0];i++) tmp+=sum[A[i]];
                    for(int i=1;i<=B[0];i++) tmp-=sum[B[i]];
                    return tmp;
                }
            }
            gotmpA; gotmpB; calmid;
            if(w<=mid) 
            {
                goleftA; goleftB;
                return getrank(l,mid,w,ty); 
            }
            else
            {
                gorightA; gorightB;
                return tmp+getrank(mid+1,r,w,ty);
            }
        }
        int getnum(int l,int r,int w)
        {
            if(l==r) return hash[l];
            int tmp=0;
            gotmpA; gotmpB; calmid;
            if(w<=tmp) 
            {
                goleftA; goleftB;
                return getnum(l,mid,w);
            }
            else
            {
                gorightA; gorightB;
                return getnum(mid+1,r,w-tmp);
            }
        }
    }
    namespace BIT
    {
        void add(int pos,int key,int val)
        {
            while(pos<=n)
            {
                CMT::insert(root[pos],1,tot,key,val);
                pos+=lowbit(pos);
            }
        }
        int Qrank(int l,int r,int k,bool ty)
        {
            preA;
            preB;
            return CMT::getrank(1,tot,k,ty);
        }
        int Qnum(int l,int r,int k)
        {
            preA;
            preB;
            return CMT::getnum(1,tot,k);
        }
        void modify(int pos,int w)
        {
            A[0]=0; int tmp=pos;
            while(pos<=n) A[++A[0]]=pos,pos+=lowbit(pos);
            for(int i=1;i<=A[0];i++) CMT::insert(root[A[i]],1,tot,a[tmp],-1);
            for(int i=1;i<=A[0];i++) CMT::insert(root[A[i]],1,tot,w,1);
            a[tmp]=w;
        }
    }
    namespace solution
    {
        struct node
        {
            int op,opl,opr,opk;
        }e[N];
        void read(int &x)
        {
            x=0; char c=getchar();
            while(!isdigit(c)) c=getchar();
            while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
        } 
        void init()
        {
            read(n); read(m);
            for(int i=1;i<=n;i++) read(a[i]),hash[i]=a[i];
            int opt,l,r,k; int tmp=n;
            for(int i=1;i<=m;i++)
            {
                read(opt);
                if(opt==3) read(l),read(k);
                else read(l),read(r),read(k);
                e[i].op=opt; e[i].opl=l; e[i].opk=k;
                if(opt!=3) e[i].opr=r;
                if(opt!=2) hash[++tmp]=k;
            }
            std::sort(hash+1,hash+tmp+1);
            tot=std::unique(hash+1,hash+tmp+1)-(hash+1);
            for(int i=1;i<=n;i++) 
            {
                a[i]=std::lower_bound(hash+1,hash+tot+1,a[i])-hash;
                BIT::add(i,a[i],1);
            }
            for(int i=1;i<=m;i++)
            if(e[i].op!=2) e[i].opk=std::lower_bound(hash+1,hash+tot+1,e[i].opk)-hash; 
        }
        void solve()
        {
            for(int i=1;i<=m;i++)
            {
                if(e[i].op==1) printf("%d
    ",BIT::Qrank(e[i].opl-1,e[i].opr,e[i].opk,0)+1);
                else if(e[i].op==2) printf("%d
    ",BIT::Qnum(e[i].opl-1,e[i].opr,e[i].opk));
                else if(e[i].op==3) BIT::modify(e[i].opl,e[i].opk);
                else if(e[i].op==4) 
                {
                    int tmp=BIT::Qrank(e[i].opl-1,e[i].opr,e[i].opk,0);
                    if(!tmp) printf("-2147483647
    ");
                    else printf("%d
    ",BIT::Qnum(e[i].opl-1,e[i].opr,tmp));
                }
                else
                {
                    int tmp=BIT::Qrank(e[i].opl-1,e[i].opr,e[i].opk,1);
                    if(tmp==e[i].opr-e[i].opl+1) printf("2147483647
    ");
                    else printf("%d
    ",BIT::Qnum(e[i].opl-1,e[i].opr,tmp+1));
                }
            }
        } 
    } 
    int main()
    {
        using namespace solution;
        init();
        solve();
    }
  • 相关阅读:
    overflow :hidden隐藏溢出用处大
    datalist 数据展示顺序
    SEO 特定搜索和外链技巧
    Android网络地址簿同步的方式
    表单全选及取消全选
    for循环的嵌套之小星星。
    数组的方法中那些会改变原数组呢?
    for循环的嵌套之打印倒三角的星星
    Js中的排他思想
    计算阶乘的思路。
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/7352738.html
Copyright © 2011-2022 走看看