序列操作 IV(树套树)

  • Description
    给出序列 a1,a2,…,an(0≤ai≤109),有关序列的两种操作。

    1. ai(1≤i≤n)变成 x(0≤x≤109)。
    2. 求 al,al+1,…,ar(1≤l≤r≤n)第 k(1≤k≤r-l+1)小。
  • 题解
    很显然,查询待修改的区间第k大一般的数据结构已经无法实现。这里给出树套树实现查询的数据结构。

线段树+权值线段树

对于每个线段树上的点维护一颗权值线段树树保存该区间所有数。容易发现对于每个修改操作复杂度是 O(nlog2n) ,而对于查询操作,先将在查询区间内的线段树中的点放入一个数组,由线段树性质得最多 logn 个,然后按照权值线段树求第k大的方法查询,时间复杂度 O(nlog2n) .

  • 注意:线段树开点应开n*4个而不是n*2个。
  • Code:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int Maxn=2e4+5;
const int Maxn2=4e6+2e5+50+Maxn;

inline int read()
{
    char ch=getchar();int i=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){i=(i<<3)+(i<<1)+ch-'0';ch=getchar();}
    return i*f;
}

int n,m,a[Maxn],tr[Maxn*2],C,lc[Maxn2],rc[Maxn2],sze[Maxn2],cnt0,rk[Maxn*2];

struct node
{
    int val,id,op;
    friend inline bool operator <(const node &a,const node &b)
    {
        return a.val<b.val;
    }
}b[Maxn*2];

struct Q
{
    int op,l,r,val;
}q[Maxn];

inline void insert2(int now,int l,int r,int val)
{
    if(l==r)
    {
        sze[now]++;
        return;
    }
    int mid=(l+r)>>1;
    if(val<=mid)
    {
        if(!lc[now])lc[now]=++C;
        insert2(lc[now],l,mid,val);
    }
    else
    {
        if(!rc[now])rc[now]=++C;
        insert2(rc[now],mid+1,r,val);
    }
    sze[now]=(lc[now]?sze[lc[now]]:0)+(rc[now]?sze[rc[now]]:0);
}

inline void insert(int k,int l,int r,int pos,int val)
{
    if(!tr[k])tr[k]=++C;
    insert2(tr[k],1,Maxn*2,val);
    if(l==r)return;
    int mid=(l+r)>>1;
    if(pos<=mid)insert(k<<1,l,mid,pos,val);
    else insert(k<<1|1,mid+1,r,pos,val);
}

inline void del2(int now,int l,int r,int val)
{
    if(l==r)
    {
        sze[now]--;
        return;
    }
    int mid=(l+r)>>1;
    if(val<=mid)
    {
        if(!lc[now])lc[now]=++C;
        del2(lc[now],l,mid,val);
    }
    else
    {
        if(!rc[now])rc[now]=++C;
        del2(rc[now],mid+1,r,val);
    }
    sze[now]=(lc[now]?sze[lc[now]]:0)+(rc[now]?sze[rc[now]]:0);
}

inline void del(int k,int l,int r,int pos,int val)
{
    if(!tr[k])tr[k]=++C;
    del2(tr[k],1,Maxn*2,val);
    if(l==r)return;
    int mid=(l+r)>>1;
    if(pos<=mid)del(k<<1,l,mid,pos,val);
    else del(k<<1|1,mid+1,r,pos,val);
}

struct num
{
    int l,r,id;
    num(){}
    num(int l,int r,int id):l(l),r(r),id(id){}
}nums[50];
int C2;

inline void getin(int k,int l,int r,int L,int R)
{
    if(l>=L&&r<=R)
    {
        nums[++C2].id=tr[k];
        nums[C2].l=1;
        nums[C2].r=Maxn*2;
        return;
    }
    int mid=(l+r)>>1;
    if(L<=mid)getin(k<<1,l,mid,L,R);
    if(R>mid)getin(k<<1|1,mid+1,r,L,R);
}

inline int calclc()
{
    int res=0;
    for(int i=1;i<=C2;i++)
    {
        res+=sze[lc[nums[i].id]];
    }
    return res;
}

inline void getinlc()
{
    for(int i=1;i<=C2;i++)
    {
        nums[i].id=lc[nums[i].id];
        nums[i].r=((nums[i].l+nums[i].r)>>1);
    }
}

inline void getinrc()
{
    for(int i=1;i<=C2;i++)
    {
        nums[i].id=rc[nums[i].id];
        nums[i].l=(((nums[i].l+nums[i].r)>>1)+1);
    }
}

inline int maxn(num x)
{
    while(x.l!=x.r)
    {
        if(sze[rc[x.id]])x.id=rc[x.id],x.l=((x.l+x.r)>>1)+1;
        else x.id=lc[x.id],x.r=((x.l+x.r)>>1);;
    }
    return x.l;
}

inline int maxlc()
{
    int res=0;
    for(int i=1;i<=C2;i++)
    {
        num x=nums[i];
        num t;
        t.id=lc[x.id];
        t.l=x.l;
        t.r=((x.l+x.r)>>1);
        res=max(res,maxn(t));
    }
    return res;
}

inline bool judgerc()
{
    for(int i=1;i<=C2;i++)
    {
        if(rc[nums[i].id])return 1;
    }
    return 0;
}

inline int maxnow()
{
    int res=0;
    for(int i=1;i<=C2;i++)
    {
        res=max(res,maxn(num(nums[i].l,nums[i].r,nums[i].id)));
    }
    return res;
}

inline int query(int l,int r,int k)
{
    memset(nums,0,sizeof(nums));
    C2=0;
    getin(1,1,n,l,r);
    while(1)
    {
        int t=calclc();
        if(t>k)
        {
            getinlc();
            continue;
        }
        else if(t==k)
        {
            return maxlc();
        }
        else if(judgerc())
        {
            k=k-t;
            getinrc();
        }
        else return maxnow();
    }
}

inline void l_b()
{
    int t=0;
    sort(b+1,b+cnt0+1);
    for(int i=1;i<=cnt0;i++)
    {
        if(i==1||b[i].val!=b[i-1].val)t++;
        rk[t]=b[i].val;
        if(b[i].op)a[b[i].id]=t;
        else q[b[i].id].val=t;
    }
}

int main()
{
    n=read(),m=read();
    for(int i=1;i<=n;i++)
    {
        b[++cnt0].val=read();
        b[cnt0].id=i;
        b[cnt0].op=1;
    }
    for(int i=1;i<=m;i++)
    {
        q[i].op=read();
        if(q[i].op==0)
        {
            q[i].l=read();
            q[i].val=read();
            b[++cnt0].val=q[i].val;
            b[cnt0].op=0;
            b[cnt0].id=i;
        }
        else
        {
            q[i].l=read();
            q[i].r=read();
            q[i].val=read();
        }
    }
    l_b();
    for(int i=1;i<=n;i++)
    {
        insert(1,1,n,i,a[i]);
    }
    for(int i=1;i<=m;i++)
    {
        int _=q[i].op;
        if(_==0)
        {
            int d=q[i].l,x=q[i].val;
            del(1,1,n,d,a[d]);
            a[d]=x; 
            insert(1,1,n,d,x);
        }
        else
        {
            int l=q[i].l,r=q[i].r,k=q[i].val;
            cout<<rk[query(l,r,k)]<<endl;
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值