首页 > 代码库 > 洛谷 3380 【模板】二逼平衡树(树状数组套权值线段树)

洛谷 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 64 2 2 1 9 4 0 1 12 1 4 33 4 102 1 4 31 2 5 94 3 9 55 2 8 5
输出样例#1:
24349

说明

时空限制:2s,128M

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

题目来源: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\n",BIT::Qrank(e[i].opl-1,e[i].opr,e[i].opk,0)+1);            else if(e[i].op==2) printf("%d\n",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\n");                else printf("%d\n",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\n");                else printf("%d\n",BIT::Qnum(e[i].opl-1,e[i].opr,tmp+1));            }        }    } } int main(){    using namespace solution;    init();    solve();}

 

洛谷 3380 【模板】二逼平衡树(树状数组套权值线段树)