bzoj 3196: Tyvj 1730 二逼平衡树

本文介绍了一种使用线段树与平衡树相结合的方法进行高效数据操作,详细解释了数据结构的设计与实现过程,包括插入、删除、查找、排名、前缀最大值与最小值以及找到大于等于或小于等于指定值的元素位置等关键操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

线段树套平衡树做法;


#include<bits/stdc++.h>
#define ls x<<1
#define rs x<<1|1
using namespace std;
const int N=200005;
const int M=3000001;
const int inf=0x3f3f3f3f;
int root[N],sum[M],s[M],ch[M][2],val[M],key[M],n,m,tot=0,a[N];
inline void up(int x){s[x]=sum[x]+s[ch[x][0]]+s[ch[x][1]];
}
int newnode(int x,int v){int t=++tot;ch[t][0]=ch[t][1]=0;val[t]=v;key[t]=rand();sum[t]=s[t]=1;return t;
}
void rotate(int& x,int d){
    int t=ch[x][d^1];ch[x][d^1]=ch[t][d];ch[t][d]=x,up(x),up(t),x=t;
}
void insert(int &x,int v){
    if(!x){x=newnode(x,v);return;}
    if(val[x]==v){sum[x]++;up(x);return;}
    int d=(val[x]<v);
    insert(ch[x][d],v);
    if(key[ch[x][d]]<key[x])rotate(x,d^1);
    up(x);
}
void del(int &x,int v){if(!x)return;
    if(val[x]==v){
        if(sum[x]>1){sum[x]--;up(x);return;}
        else{
            if(ch[x][0]*ch[x][1]==0){int k=ch[x][1]+ch[x][0];x=k;return;}
            int d=(key[ch[x][0]]<key[ch[x][1]]);
            rotate(x,d);del(ch[x][d],v);
        }
    }
    del(ch[x][val[x]<v],v);
    up(x);
}
int getrank(int x,int v){if(!x)return 0;
    if(val[x]==v)return s[ch[x][0]];
    if(val[x]<v)return s[ch[x][0]]+sum[x]+getrank(ch[x][1],v);
    else return getrank(ch[x][0],v);
}
int getpro(int x,int v){if(!x)return -inf;
    if(val[x]<v)return max(val[x],getpro(ch[x][1],v));
    else return getpro(ch[x][0],v);
}
int getaft(int x,int v){if(!x)return inf;
    if(val[x]>v)return min(val[x],getaft(ch[x][0],v));
    else return getaft(ch[x][1],v);
}
void build(int x,int l,int r,int pos,int v){
    insert(root[x],v);
    if(l==r)return;
    int mid=(l+r)>>1;
    if(pos<=mid)build(ls,l,mid,pos,v);
    else build(rs,mid+1,r,pos,v);
}
int rank(int x,int l,int r,int ql,int qr,int v){int ans=0;
    if(l>=ql && r<=qr){return getrank(root[x],v);}
    int mid=(l+r)>>1;
    if(ql<=mid)ans+=rank(ls,l,mid,ql,qr,v);
    if(qr>mid)ans+=rank(rs,mid+1,r,ql,qr,v);
    return ans;
}
int kth(int ql,int qr,int k){
    int l=0,r=inf,ans;
    while(l<=r){int mid=(l+r)>>1;
        if(rank(1,1,n,ql,qr,mid)<=k-1){l=mid+1;ans=mid;}   ///
        else r=mid-1;
    }
    return ans;
}
void change(int x,int l,int r,int pos,int v){
    del(root[x],a[pos]);insert(root[x],v);
    if(l==r)return;
    int mid=(l+r)>>1;
    if(pos<=mid)change(ls,l,mid,pos,v);
    else change(rs,mid+1,r,pos,v);
}
int pro(int x,int l,int r,int ql,int qr,int v){int ans=-inf;
    if(l>=ql && r<=qr){return getpro(root[x],v);}
    int mid=(l+r)>>1;
    if(ql<=mid)ans=max(ans,pro(ls,l,mid,ql,qr,v));
    if(qr>mid)ans=max(ans,pro(rs,mid+1,r,ql,qr,v));
    return ans;
}
int aft(int x,int l,int r,int ql,int qr,int v){int ans=inf;
    if(l>=ql && r<=qr){return getaft(root[x],v);}
    int mid=(l+r)>>1;
    if(ql<=mid)ans=min(ans,aft(ls,l,mid,ql,qr,v));
    if(qr>mid)ans=min(ans,aft(rs,mid+1,r,ql,qr,v));
    return ans;
}
void debug(int x) {
        if(!x)return;
        debug(ch[x][0]);
        printf("%d :( val: %d sum: %d size: %d ls:%d rs: %d)\n",x,val[x], sum[x],s[x], ch[x][0], ch[x][1]);
        debug(ch[x][1]);
    }
void bug(int x,int l,int r){
    printf("root[%d] %d %d \n",x,l,r);debug(root[x]);
    if(l==r)return;
    int mid=(l+r)>>1;
    bug(ls,l,mid);bug(rs,mid+1,r);
}
int main(){
//freopen("in.in","r",stdin);
//freopen("out.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)build(1,1,n,i,a[i]);
    for(int i=1;i<=m;i++)
    {
        int f;scanf("%d",&f);
        int x,y,k;
        switch(f)
        {
            case 1:scanf("%d%d%d",&x,&y,&k);printf("%d\n",rank(1,1,n,x,y,k)+1);break;
            case 2:scanf("%d%d%d",&x,&y,&k);printf("%d\n",kth(x,y,k));break;
            case 3:scanf("%d%d",&x,&y);change(1,1,n,x,y);a[x]=y;break;
            case 4:scanf("%d%d%d",&x,&y,&k);printf("%d\n",pro(1,1,n,x,y,k));break;
            case 5:scanf("%d%d%d",&x,&y,&k);printf("%d\n",aft(1,1,n,x,y,k));break;
        } 
    }
//    printf("\n\n");bug(1,1,n);
    return 0;
}

好慢…难道说这题的意思是用平衡树的都是…….

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值