BZOJ3196 || 洛谷P3380 二逼平衡树【树套树】

Time Limit: 10 Sec
Memory Limit: 128 MB

Description

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

Input

第一行两个数 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的后继

Output

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

HINT

1.n和m的数据范围:n,m<=50000
2.序列中每个数的数据范围:[0,1e8]
3.虽然原题没有,但事实上5操作的k可能为负数

洛谷题面4,5操作稍有不同,但以下程序依然适用


题目分析:

树套树的方式多种多样
这里先讲一讲线段树套Treap

思路非常的暴力
线段树每个结点都是一棵treap
用来维护该区间内的数

1.rank操作,在线段树找到对应区间,将每个区间的排名加起来
2.kth操作,直接二分数值,将二分数值在给定区间内rank,看是否等于k
3.modify操作,直接暴力将原数从每个treap中删除在插入新数
4.5.pre.nxt操作,找到线段树对应区间查询


#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;

int read()
{
    int f=1,x=0;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return f*x;
}

const int inf=2147483647;
const int maxn=2000010;
int n,m;
int a[maxn],val[maxn],r[maxn];
int sum[maxn],cnt[maxn],ch[maxn][2],tot;
int rt[maxn];//rt[]表示线段树每个节点保存的treap的树根

void update(int p){ sum[p]=cnt[p]+sum[ch[p][0]]+sum[ch[p][1]];}

void rotate(int &p,int d)
{
    int k=ch[p][d^1];
    ch[p][d^1]=ch[k][d];
    ch[k][d]=p;
    update(p); update(k);
    p=k;
}

void ins(int &p,int x)//和普通treap的插入一样
{
    if(!p)
    { 
        p=++tot; val[p]=x; r[p]=rand(); 
         sum[p]=cnt[p]=1;
        return;
    }
    if(val[p]==x){ ++sum[p]; ++cnt[p]; return;}
    int d=x<val[p] ?0:1;
    ins(ch[p][d],x);
    if(r[ch[p][d]]<r[p]) rotate(p,d^1);
    update(p);
}

void build(int s,int t,int p)
{
    for(int i=s;i<=t;++i) ins(rt[p],a[i]);//建立该区间的treap
    if(s==t) return;
    int mid=s+t>>1;
    build(s,mid,p<<1); build(mid+1,t,p<<1|1);
}

int rank_treap(int p,int x)//和普通treap的rank一样
{
    if(!p) return 0;
    if(val[p]==x) return sum[ch[p][0]];
    if(x<val[p]) return rank_treap(ch[p][0],x);
    else return sum[ch[p][0]]+cnt[p]+rank_treap(ch[p][1],x);
}

int rank_seg(int ll,int rr,int s,int t,int p,int v)//线段树找对应区间,排名相加
{
    if(ll<=s&&t<=rr) return rank_treap(rt[p],v);
    int mid=s+t>>1,ans=0;
    if(ll<=mid) ans+=rank_seg(ll,rr,s,mid,p<<1,v);
    if(rr>mid) ans+=rank_seg(ll,rr,mid+1,t,p<<1|1,v);
    return ans;
}

int kth(int ll,int rr,int k)//暴力二分再rank
{
    int L=0,R=1e8,mid;
    while(L<R)
    {
        mid=L+R+1>>1;
        if(rank_seg(ll,rr,1,n,1,mid)>=k) R=mid-1;
        else L=mid;
    }
    return L;
}

void del(int &p,int x)//普通treap的del
{
    if(!p) return;
    if(val[p]==x)
    {
        if(cnt[p]>1){ --sum[p]; --cnt[p]; return;}
        else
        {
            if(!ch[p][0]) p=ch[p][1];
            else if(!ch[p][1]) p=ch[p][0];
            else
            {
                int dd=r[ch[p][0]]<r[ch[p][1]] ?1:0;
                rotate(p,dd); del(ch[p][dd],x);
            }
        }
    }
    else if(x<val[p]) del(ch[p][0],x);
    else del(ch[p][1],x);
    if(p) update(p);
}

void modify(int s,int t,int p,int pos,int val)
{
    del(rt[p],a[pos]); ins(rt[p],val);//暴力删除再重新插入
    if(s==t) return;
    int mid=s+t>>1;
    if(pos<=mid) modify(s,mid,p<<1,pos,val);//相当于线段树的单点修改
    else modify(mid+1,t,p<<1|1,pos,val);
}

int pre_treap(int p,int x)
{
    if(!p)return -inf;//没有前驱返回-inf
    if(x<=val[p]) return pre_treap(ch[p][0],x);//找到一个,但不能确定是最大的
    return max(val[p],pre_treap(ch[p][1],x));
}

int nxt_treap(int p,int x)//同pre
{
    if(!p)return inf;
    if(x>=val[p]) return nxt_treap(ch[p][1],x);
    return min(val[p],nxt_treap(ch[p][0],x));
}

int pre_seg(int ll,int rr,int s,int t,int p,int v)
{
    if(ll<=s&&t<=rr) return pre_treap(rt[p],v);
    int mid=s+t>>1,ans=-inf;
    if(ll<=mid) ans=max(ans,pre_seg(ll,rr,s,mid,p<<1,v));
    if(rr>mid) ans=max(ans,pre_seg(ll,rr,mid+1,t,p<<1|1,v));
    return ans;
}

int nxt_seg(int ll,int rr,int s,int t,int p,int v)
{
    if(ll<=s&&t<=rr) return nxt_treap(rt[p],v);
    int mid=s+t>>1,ans=inf;
    if(ll<=mid) ans=min(ans,nxt_seg(ll,rr,s,mid,p<<1,v));
    if(rr>mid) ans=min(ans,nxt_seg(ll,rr,mid+1,t,p<<1|1,v));
    return ans;
}

int main()
{
    n=read();m=read();
    for(int i=1;i<=n;++i)a[i]=read();
    build(1,n,1);//线段树套treap建树
    while(m--)
    {
        int k=read(),ll=read(),rr=read();
        if(k==1) printf("%d\n",rank_seg(ll,rr,1,n,1,read())+1);
        else if(k==2) printf("%d\n",kth(ll,rr,read()));
        else if(k==3) modify(1,n,1,ll,rr),a[ll]=rr;
        else if(k==4) printf("%d\n",pre_seg(ll,rr,1,n,1,read()));
        else if(k==5) printf("%d\n",nxt_seg(ll,rr,1,n,1,read()));
    }
    return 0;
}
weixin073智慧旅游平台开发微信小程序+ssm后端毕业源码案例设计 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
python017基于Python贫困生资助管理系统带vue前后端分离毕业源码案例设计 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值