hdu 2665 Kth number 可持(逗)久(比)化线段树

题意:链接

方法:可持(逗)久(比)化线段树

解析:

对于一个序列,多次询问一段区间的第K小的数是多少。

树套树是俩log,并且难写!

所以我们的可持久化线段树的优越性就体现出来了,少了一个log并且很好写?

跟上一道题的建树一样,在询问的时候,只需要二分一下就简单的过去了。

不过离散化后,序列的长度要注意不要写成原来的n!!!!!

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 100100
using namespace std;
int a[N];
int uni[N];
struct node
{
    int lson,rson,sum;
}seg[N*20];
int root[N];
int t;
int size;
void build(int l,int r,int &rt)
{
    rt=++size;
    seg[rt].sum=0;
    if(l==r)return;
    int mid=(l+r)>>1;
    build(l,mid,seg[rt].lson);
    build(mid+1,r,seg[rt].rson);
}
void update(int p,int &q,int l,int r,int v)
{
    q=++size;
    seg[q]=seg[p];
    seg[q].sum++;
    if(l==r)return;
    int mid=(l+r)>>1;
    if(v<=mid)update(seg[p].lson,seg[q].lson,l,mid,v);
    else update(seg[p].rson,seg[q].rson,mid+1,r,v);
}
int que(int L,int R,int l,int r,int k)
{
    if(l==r)return l;
    int mid=(l+r)>>1;
    int tmp=seg[seg[R].lson].sum-seg[seg[L].lson].sum;
    if(tmp>=k)
    {
        return que(seg[L].lson,seg[R].lson,l,mid,k);
    }else
    {
        return que(seg[L].rson,seg[R].rson,mid+1,r,k-tmp);
    }
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        int n,q;
        scanf("%d%d",&n,&q);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            uni[i]=a[i];
        }
        size=0;
        sort(uni+1,uni+n+1);
        int tot=unique(uni+1,uni+n+1)-uni-1;
        build(1,tot,root[0]);
        for(int i=1;i<=n;i++)
        {
            a[i]=lower_bound(uni+1,uni+1+tot,a[i])-uni;
        }
        for(int i=1;i<=n;i++)
        {
            update(root[i-1],root[i],1,tot,a[i]);
        }
        for(int i=1;i<=q;i++)
        {
            int l,r,k;
            scanf("%d%d%d",&l,&r,&k);
            int debug;
            int j=que(root[l-1],root[r],1,tot,k);
            printf("%d\n",uni[j]);
        }
    }
}

你可能感兴趣的:(代码,方法,序列,持久化,离散化)