树套树

树套树

线段树套平衡树

在平衡树操作的基础上加上区间的限制,就需要用树套树了

线段树套平衡树就是线段树的每一个节点都是一棵平衡树

线段树管理区间,平衡树维护区间中数的信息

平衡树用的常数较小的\(treap\)粘的,就不讲了,下面是线段树部分

建树

建线段树的时候把对应的数加入平衡树

il void build(int rt,int l,int r) {
    for(ri int i=l;i<=r;++i) treap::ins(rot[rt],p[i]);
    if(l^r){
        ri int mid=(l+r)>>1;
        build(ls(rt),l,mid);
        build(rs(rt),mid+1,r);
    }
}

查询区间排名

在线段树上找到对应区间,每个节点的平衡树内查询对应数的排名并求和,复杂度 \(O(\log^2 n)\)

il int rnk(int rt,int l,int r,int ql,int qr,int k) {
    if(ql<=l&&r<=qr) return treap::rnk(rot[rt],k);
    ri int as=0,mid=(l+r)>>1;
    if(mid>=ql) as+=rnk(ls(rt),l,mid,ql,qr,k);
    if(mid<qr) as+=rnk(rs(rt),mid+1,r,ql,qr,k);
    return as;
}

查询区间第 \(k\)

\(\log n\) 二分答案,\(\log^2 n\) 检查 \(mid\) 的排名是否为 \(k\),复杂度 \(O(\log^3 n)\)

il int kth(int ql,int qr,int k) {
    ri int l=0,r=1e8,mid;
    while(l<r) {
        mid=(l+r+1)>>1;  //
        if(rnk(1,1,n,ql,qr,mid)<k) l=mid;
        else r=mid-1;
    }
    return r;
}

单点修改

在线段树上找到所有包含该点的区间,在所有区间对应的平衡树中删除原数,加入新数,复杂度 \(O(\log^2 n)\)

il void upd(int rt,int l,int r,int pos,int k) {
    treap::del(rot[rt],p[pos]);
    treap::ins(rot[rt],k);
    if(l^r) {
        ri int mid=(l+r)>>1;
        if(pos <= mid) upd(ls(rt),l,mid,pos,k);
        else upd(rs(rt),mid+1,r,pos,k);
    }
}

查询区间前驱

对所有区间分别查询,答案取 \(max\),复杂度 \(O(\log^2 n)\)

il int pre(int rt,int l,int r,int ql,int qr,int k) {
    if(ql<=l&&r<=qr) return treap::pre(rot[rt],k);
    ri int as=-inf, mid=(l+r)>>1;
    if(mid>=ql) as=max(as,pre(ls(rt),l,mid,ql,qr,k));
    if(mid<qr) as=max(as,pre(rs(rt),mid+1,r,ql,qr,k));
    return as;
}

查询区间后继

对所有区间分别查询,答案取 \(min\),复杂度 \(O(\log^2 n)\)

il int nxt(int rt, int l, int r, int ql, int qr, int k) {
    if(ql<=l&&r<=qr) return treap::nxt(rot[rt],k);
    ri int as=inf,mid=(l+r)>>1;
    if(mid>=ql) as=min(as,nxt(ls(rt),l,mid,ql,qr,k));
    if(mid<qr) as=min(as,nxt(rs(rt),mid+1,r,ql,qr,k));
    return as;
}
code
//不开o2可过qwq
#include <bits/stdc++.h>
#define il inline
#define cs const
#define ri register
#define F(s) freopen(#s".in","r",stdin),freopen(#s".out","w",stdout);            
using namespace std;

namespace Q{
    il int rd(){
        ri int x=0;ri bool f=0;ri char c=getchar();
        while(!isdigit(c)) f|=(c==45),c=getchar();
        while(isdigit(c)) x=x*10+(c^48),c=getchar();
        return f?-x:x;
    }
    il void wt(int x){
        if(x<0) x=-x,putchar(45);
        if(x>=10) wt(x/10);
        return putchar(x%10|48),void();
    }
} using namespace Q;

cs int N=5e4+5,inf=2147483647;
int p[N],n,m;

namespace treap{
    int id;
    mt19937 srd(314);
    struct tree{int s[2],vl,dt,ct,sz;} t[N*40];
    il void upd(cs int &i){
        t[i].sz=t[i].ct+t[t[i].s[0]].sz+t[t[i].s[1]].sz;
        return;
    }
    il void rtt(int &i,cs bool d){//1zig 0zag
        int o=t[i].s[d^1];
        t[i].s[d^1]=t[o].s[d];
        t[o].s[d]=i,t[o].sz=t[i].sz;
        return upd(i),i=o,void();
    }
    il int add(cs int &x){
        t[++id].vl=x,t[id].dt=srd(),t[id].sz=t[id].ct=1;
        t[id].s[0]=t[id].s[1]=0;return id;
    } 
    il void ins(int &i,cs int &x){
        if(!i) return i=add(x),void();
        else t[i].sz++;
        if(t[i].vl==x) t[i].ct++;
        else{
            bool d=(t[i].vl<x);
            ins(t[i].s[d],x);
            if(t[t[i].s[d]].dt<t[i].dt) rtt(i,d^1);
        }
        return;
    }
    il void del(int &i,cs int &x){
        if(t[i].vl==x){
            if(t[i].ct>1) t[i].ct--,t[i].sz--;
            else if(!(t[i].s[0]*t[i].s[1])) i=t[i].s[0]+t[i].s[1];
            else{
                bool d=(t[t[i].s[0]].dt<t[t[i].s[1]].dt);
                rtt(i,d),del(i,x);
            }
            return;
        }
        return t[i].sz--,del(t[i].s[(x>t[i].vl)],x);
    }
    il int rnk(int rt,cs int &x){
        ri int i=rt,rk=0;//
        while(i){
            if(x==t[i].vl) return rk+t[t[i].s[0]].sz;
            if(x<t[i].vl) i=t[i].s[0];
            else rk+=t[t[i].s[0]].sz+t[i].ct,i=t[i].s[1];
        }
        return rk;
    }	
    il int kth(int rt,int x){
        ri int i=rt;
        while(i){
            if(t[t[i].s[0]].sz<x&&t[t[i].s[0]].sz+t[i].ct>=x) return t[i].vl;
            if(t[t[i].s[0]].sz>=x) i=t[i].s[0];
            else x-=t[t[i].s[0]].sz+t[i].ct,i=t[i].s[1];
        }
        return 0;
    }
    il int pre(int rt,cs int &x){
        ri int i=rt,as=-inf;
        while(i){
            if(t[i].vl<x) as=t[i].vl,i=t[i].s[1];
            else i=t[i].s[0];
        }
        return as;
    }
    il int nxt(int rt,cs int &x){
        ri int i=rt,as=inf;
        while(i){
            if(t[i].vl>x) as=t[i].vl,i=t[i].s[0];
            else i=t[i].s[1];
        }
        return as;
    }
}  

namespace xds {
    #define ls(rt) (rt<<1)
    #define rs(rt) (rt<<1|1)
    int rot[N<<4];
    il void build(int rt,int l,int r) {
        for(ri int i=l;i<=r;++i) treap::ins(rot[rt],p[i]);
        if(l^r){
            ri int mid=(l+r)>>1;
            build(ls(rt),l,mid);
            build(rs(rt),mid+1,r);
        }
    }
    il void upd(int rt,int l,int r,int pos,int k) {
        treap::del(rot[rt],p[pos]);
        treap::ins(rot[rt],k);
        if(l^r) {
            ri int mid=(l+r)>>1;
            if(pos <= mid) upd(ls(rt),l,mid,pos,k);
            else upd(rs(rt),mid+1,r,pos,k);
        }
    }
    il int rnk(int rt,int l,int r,int ql,int qr,int k) {
        if(ql<=l&&r<=qr) return treap::rnk(rot[rt],k);
        ri int as=0,mid=(l+r)>>1;
        if(mid>=ql) as+=rnk(ls(rt),l,mid,ql,qr,k);
        if(mid<qr) as+=rnk(rs(rt),mid+1,r,ql,qr,k);
        return as;
    }
    il int kth(int ql,int qr,int k) {
        ri int l=0,r=1e8,mid;
        while(l<r) {
            mid=(l+r+1)>>1;  //
            if(rnk(1,1,n,ql,qr,mid)<k) l=mid;
            else r=mid-1;
        }
        return r;
    }
    il int pre(int rt,int l,int r,int ql,int qr,int k) {
        if(ql<=l&&r<=qr) return treap::pre(rot[rt],k);
        ri int as=-inf, mid=(l+r)>>1;
        if(mid>=ql) as=max(as,pre(ls(rt),l,mid,ql,qr,k));
        if(mid<qr) as=max(as,pre(rs(rt),mid+1,r,ql,qr,k));
        return as;
    }
    il int nxt(int rt, int l, int r, int ql, int qr, int k) {
        if(ql<=l&&r<=qr) return treap::nxt(rot[rt],k);
        ri int as=inf,mid=(l+r)>>1;
        if(mid>=ql) as=min(as,nxt(ls(rt),l,mid,ql,qr,k));
        if(mid<qr) as=min(as,nxt(rs(rt),mid+1,r,ql,qr,k));
        return as;
    }
    #undef ls
    #undef rs
}

signed main() {
    n=rd(),m=rd();
    for(ri int i=1;i<=n;++i) p[i]=rd();
    xds::build(1,1,n);
    for(ri int i=1,op,l,r,k;i<=m;++i) {
        op=rd();
        switch (op){
        case 1:
            l=rd(),r=rd(),k=rd();
            wt(xds::rnk(1,1,n,l,r,k)+1);
            putchar(10);
            break;
        case 2:
            l=rd(),r=rd(),k=rd();
            wt(xds::kth(l,r,k));
            putchar(10);
            break;
        case 3:
            l=rd(),k=rd();
            xds::upd(1,1,n,l,k);
            p[l]=k;  
            break;
        case 4:
            l=rd(),r=rd(),k=rd();
            wt(xds::pre(1,1,n,l,r,k));
            putchar(10);  
            break;           
        default:
            l=rd(),r=rd(),k=rd();
            wt(xds::nxt(1,1,n,l,r,k));
            putchar(10);        
            break;
        }
    }
    return 0;
}

edit

posted @ 2023-03-30 21:34  雨夜风月  阅读(56)  评论(0编辑  收藏  举报