HDU 2665 Kth number 可持久化线段树

题意:给n个数和m个询问,询问l,r,k是从l~r中的第k小
思路:可持久化线段树的模板题
说下自己对可持久化线段树的理解吧
可持久化线段树的是可以保存历史版本的线段树,就是插进去第i个数的线段树的状态,这样我们可以通过state[r]-state[l-1]来得到state[l~r]
朴素做法就是维护n颗线段树,但是这样一般都会MLE
可持久化线段树利用了每次插入数只修改了线段树上一条链的特性来每次插入一个数只新建一条链来维护历史版本,空间复杂度O(n*logn+n*logn) 原树+新建的链
这样我们可以通过上述做法在得到state[l~r]

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<queue>
#include<stack>
#include<string>
#include<vector>
#include<map>
#include<set>
using namespace std;
#define lowbit(x) (x&(-x))
typedef long long LL;
#define maxn 100005
const int inf=(1<<28)-1;
struct Seg_node
{
    int lson,rson,sum;
};
int cmp(int a,int b)
{
    return a>b;
}
class Segment
{
    public:
    int A[maxn],h[maxn];//原数组和hash后的数组
    int Size1,Size2;//原数组和hash后的数组大小
    int root[maxn];//root[i]表示第i棵树的根节点
    int tot;//节点个数 
    Seg_node seg[maxn*20];//树的节点
    void init()
    {
        tot=0;
    }
    void hash_array(int chs=0)//chs=0从小到大 
    {
        for(int i=1;i<=Size1;++i)
        h[i]=A[i];
        if(chs) sort(h+1,h+Size1+1,cmp);
        else sort(h+1,h+Size1+1);
        Size2=1;
        for(int i=2;i<=Size1;++i)
        if(h[i]!=h[i-1]) h[++Size2]=h[i];
    }
    void build(int l,int r,int& rt)//因为要给每个节点找左右儿子,所以& 
    {
        rt=++tot;
        seg[rt].sum=0;
        if(l==r) return ;
        int mid=(l+r)/2;
        build(l,mid,seg[rt].lson);
        build(mid+1,r,seg[rt].rson);
    }
    void update(int last,int k,int l,int r,int& rt)
    {
        rt=++tot;
        seg[rt]=seg[last];
        seg[rt].sum++;
        if(l==r) return ;
        int mid=(l+r)/2;
        if(k<=mid) update(seg[last].lson,k,l,mid,seg[rt].lson);
        else update(seg[last].rson,k,mid+1,r,seg[rt].rson);
    }
    int query(int rt1,int rt2,int l,int r,int k)
    {
        if(l==r) return l;
        int cnt=seg[seg[rt2].lson].sum-seg[seg[rt1].lson].sum;
        int mid=(l+r)/2;
        if(k<=cnt)
        return query(seg[rt1].lson,seg[rt2].lson,l,mid,k);
        else
        return query(seg[rt1].rson,seg[rt2].rson,mid+1,r,k-cnt);
    }
    int find(int x)
    {
        int l=1,r=Size2;
        while(l<=r)
        {
            int mid=(l+r)/2;
            if(h[mid]==x) return mid;
            if(h[mid]>x) r=mid-1;
            else l=mid+1;
        }
        return l;
    }
    void fun()//更新1~n的点的链 
    {
        init();
        hash_array();
        build(1,Size2,root[0]);
        for(int i=1;i<=Size1;++i)
        {
            int pos=find(A[i]);
            update(root[i-1],pos,1,Size2,root[i]);
        }
    }
    int Get_k(int l,int r,int k)
    {
        int tmp=query(root[l-1],root[r],1,Size2,k);
        return h[tmp];
    }
}Seg;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        Seg.Size1=n;
        for(int i=1;i<=n;++i)
        scanf("%d",&Seg.A[i]);
        Seg.fun();
        for(int i=1;i<=m;++i)
        {
            int l,r,k;
            scanf("%d%d%d",&l,&r,&k);
            printf("%d\n",Seg.Get_k(l,r,k));
        }
    }
    return 0;
}

你可能感兴趣的:(可持久化线段树)