[bzoj3196]Tyvj 1730 二逼平衡树

来自FallDream的博客,未经允许,请勿转载。


您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
1.查询k在区间内的排名
2.查询区间内排名为k的值
3.修改某一位值上的数值
4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)
5.查询k在区间内的后继(后继定义为大于x,且最小的数)

n,m<=50000   1s/128MB

这道题我是不知道怎么做 传统的动态区间k大都可以实现这些操作 但是

线段树套权值线段树:时间nlog^2n 空间nlog^2n 这道题空间卡成这样 理论上讲是不够的

线段树套平衡树 空间只有nlogn 但是时间nlog^3n 这居然能过????

不管  数据水,所以上面两个都能过  比较好奇出题人写的啥优秀做法。

#include<iostream>
#include<cstdio>
#include<algorithm>
#define MV 10000000
#define MN 50000
#define N 65536
using namespace std;
inline int read()
{
    int x = 0 , f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}
struct ques{int op,l,r,x;}q[MN+5];
struct Tree{int l,r,x;}T[MV];
int n,m,rt[N*2+5],a[MN+5],tot,cnt=0,J=1,l[MN*2+5],R[MN+5],rtnum;

void Add(int x,int lt,int rt,int v,int ad)
{ 
    T[x].x+=ad;
    if(lt==rt) return;
    int mid=lt+rt>>1;
    if(v<=mid) Add(!T[x].l?T[x].l=++cnt:T[x].l,lt,mid,v,ad);
    else Add(!T[x].r?T[x].r=++cnt:T[x].r,mid+1,rt,v,ad); 
}
void Modify(int x,int v,int ad){for(x+=N;x;x>>=1) Add(rt[x],1,J,v,ad);}

void GetRt(int l,int r)
{
    for(rtnum=0,l+=N-1,r+=N+1;l^r^1;l>>=1,r>>=1)
    {
        if(~l&1) R[++rtnum]=rt[l+1];
        if( r&1) R[++rtnum]=rt[r-1];
    }
}

int GetRk(int v)
{
    if(!v) return 1;
    int l=1,r=J,mid,ans=1;
    while(l<r)
    {
        mid=l+r>>1;
        if(v<=mid)
        {
            r=mid;
            for(int j=1;j<=rtnum;++j) R[j]=T[R[j]].l; 
        }
        else
        {
            l=mid+1;
            for(int j=1;j<=rtnum;++j) ans+=T[T[R[j]].l].x,R[j]=T[R[j]].r; 
        } 
    }
    for(int j=1;j<=rtnum;++j) ans+=T[R[j]].x;
    return ans;
}

int GetNum(int rk)
{
    int l=1,r=J,mid,sum;
    while(l<r)
    {
        mid=l+r>>1;sum=0;
        for(int i=1;i<=rtnum;++i)
            sum+=T[T[R[i]].l].x;
        if(sum<rk) 
        {
            rk-=sum;l=mid+1;
            for(int i=1;i<=rtnum;++i) R[i]=T[R[i]].r; 
        }
        else
        {
            r=mid;
            for(int i=1;i<=rtnum;++i) R[i]=T[R[i]].l;    
        }
    }
    return l;
}

int main()
{
    tot=n=read();m=read();
    for(int i=1;i<=N<<1;++i) rt[i]=++cnt; 
    for(int i=1;i<=n;++i) l[i]=a[i]=read();
    for(int i=1;i<=m;++i)
    {
        q[i].op=read();q[i].l=read();q[i].r=read();
        if(q[i].op!=3) q[i].x=read();
        else l[++tot]=q[i].r;    
    }
    sort(l+1,l+tot+1);
    for(int i=2;i<=tot;++i) if(l[i]!=l[i-1]) l[++J]=l[i]; 
    for(int i=1;i<=n;++i) Modify(i,a[i]=lower_bound(l+1,l+J+1,a[i])-l,1);
    for(int i=1;i<=m;++i)
    {
        if(q[i].op==3)
        {
            Modify(q[i].l,a[q[i].l],-1);
            Modify(q[i].l,q[i].r=lower_bound(l+1,l+J+1,q[i].r)-l,1);
            a[q[i].l]=q[i].r;
        } 
        else 
        {
            GetRt(q[i].l,q[i].r);    
            if(q[i].op==1) printf("%d
",GetRk(lower_bound(l+1,l+J+1,q[i].x)-l-1));
            if(q[i].op==2) printf("%d
",l[GetNum(q[i].x)]);
            if(q[i].op==4) 
            {
                int rk=GetRk(lower_bound(l+1,l+J+1,q[i].x)-l-1)-1;
                GetRt(q[i].l,q[i].r);
                printf("%d
",l[GetNum(rk)]); 
            }
            if(q[i].op==5) 
            {
                int rk=GetRk(upper_bound(l+1,l+J+1,q[i].x)-l-1); 
                GetRt(q[i].l,q[i].r);
                printf("%d
",l[GetNum(rk)]); 
            } 
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/FallDream/p/bzoj3196.html