主席树模板

主席树模板

 主要用来查询区间第k小

insert操作
int insert(int o, int x)
{
    int now=++len,root,l=1,r=m,mid;
    root=now; s(now)=s(o)+1;
    while(l < r)
    {
        mid=(l+r)/2;
        if(x<=mid){
            l(now)=++len; r(now)=r(o);
            o=l(o); now=len; r=mid;
        } else {
            r(now)=++len; l(now)=l(o);
            o=r(o); now=len; l=mid+1;
        }
        s(now)=s(o)+1;
    }
    return root;
}
查询操作
int query(int L, int R, int k)
{
    int l=1, r=m, mid;
    while(l<r)
    {
        mid=(l+r)/2;
        if(k<=s(l(R))-s(l(L))){
            r=mid; R=l(R); L=l(L);
        } else {
            l=mid+1; k-=s(l(R))-s(l(L));
            R=r(R); L=r(L);
        }
    }
    return l;
}

模板题

NEERC 2004 K小数
http://cogs.pro:8080/cogs/problem/problem.php?pid=1534

完整模板
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cstdlib>
    #define File(x) "kthnumber."#x
    #define For(i,s,e) for(int i=(s); i<=(e); i++)
    #define Rep(i,s,e) for(int i=(s); i>=(e); i--)
    using namespace std;

    const int N=100000*30+10;
    struct HJT
    {
        int l,r,size;
        #define l(x) T[x].l
        #define r(x) T[x].r
        #define s(x) T[x].size
    }T[N];

    int a[N],to[N],h[N],m,n,Q,len;

    void read(int &x)
    {
        char ch; int s=1;
        while(ch=getchar(),ch>'9' || ch<'0') if(ch=='-') s=-1;
        x=ch-'0';
        while(ch=getchar(),ch>='0' && ch<='9') x=x*10+ch-'0';
        x*=s;
    }
    void init()
    {
        memcpy(to, a, sizeof(a));
        sort(to+1,to+1+n);
        m=unique(to+1,to+1+n)-to-1;
    }
    int hash(int x)
    {
        return lower_bound(to+1, to+1+m, x)-to;
    }
    int build(int l, int r)
    {
        int o=++len, mid((l+r)/2);
        s(o)=0;
        if(l!=r)
        {
            l(o)=build(l,mid); r(o)=build(mid+1,r);
        }
        return o;
    }
    int insert(int o, int x)
    {
        int now=++len,root,l=1,r=m,mid;
        root=now; s(now)=s(o)+1;
        while(l<r)
        {
            mid=(l+r)/2;
            if(x<=mid){
                l(now)=++len; r(now)=r(o);
                o=l(o); now=len; r=mid;
            } else {
                r(now)=++len; l(now)=l(o);
                o=r(o); now=len; l=mid+1;
            }
            s(now)=s(o)+1;
        }
        return root;
    }
    int query(int L, int R, int k)
    {
        int l=1, r=m, mid;
        while(l<r)
        {
            mid=(l+r)/2;
            if(k<=s(l(R))-s(l(L))){
                r=mid; R=l(R); L=l(L);
            } else {
                l=mid+1; k-=s(l(R))-s(l(L));
                R=r(R); L=r(L);
            }
        }
        return l;
    }

    int main()
    {
        freopen(File(in),"r",stdin);
        freopen(File(out),"w",stdout);

    //  ios::sync_with_stdio(false);

        read(n); read(Q);
        For(i,1,n) read(a[i]);
        init();
        h[0]=build(1,m);
        For(i,1,n) h[i]=insert(h[i-1],hash(a[i]));
        while(Q--)
        {
            int l,r,k;
            read(l); read(r); read(k);
            printf("%d\n",to[query(h[l-1],h[r],k)]);
        }

        return 0;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值