HDU 2665 Kth number (静态主席树模板)

静态主席树,用于查找区间内第k大的数字,空间复杂度4*n+nlog2(n),时间复杂度(n+q)log2(n)

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<ctime>
#include<algorithm>
#define eps 1e-14
#define pi acos(-1)
#define ll long long
#define RD T*(rand()*2-RAND_MAX)
#define Drand (long double)rand()/RAND_MAX
#define LINF 1e18
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=1e5+10;
const int mod=1e4+7;

int tot=0;//记录树的节点在一维数组中的位置
int aa[maxn],a[maxn],L[maxn*21],R[maxn*21],sum[maxn*21],T[maxn];
//aa是原来顺序的数,a离散排序过后的
//L数组表示第 i 个节点,其左节点所在的位置
//R就是右节点所在位置,LR用来找左右子树
//sum记录数字出现的前缀和
//T记录各个树的根节点位置
void build(int l,int r,int &rt) //建立空的树,第0颗树就是空树
{
    rt=++tot;
    sum[rt]=0;
    if(l==r)return;
    int mid=(l+r)>>1;
    build(l,mid,L[rt]);
    build(mid+1,r,R[rt]);
}

void update(int l,int r,int &rt,int pre,int x)//每个节点建树
{
    rt=++tot;
    L[rt]=L[pre];
    R[rt]=R[pre];
    sum[rt]=sum[pre]+1;
    if(l==r)return;
    int mid=(l+r)>>1;
    if(x<=mid)update(l,mid,L[rt],L[pre],x);
    else update(mid+1,r,R[rt],R[pre],x);
}

int query(int l,int r,int tl,int tr,int k)
{
    if(l==r)return l;
    int mid=(l+r)>>1;
    int res=sum[ L[tr] ] - sum[ L[tl] ];
    if(res>=k)query(l,mid,L[tl],L[tr],k);
    else query(mid+1,r,R[tl],R[tr],k-res);
}

int main()
{
//    freopen("in.txt","r",stdin);
    int t;
    scanf("%d",&t);
    while(t--){
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",&aa[i]),a[i]=aa[i];
        sort(a+1,a+1+n);
        int num=unique(a+1,a+1+n)-a-1;
        tot=0;
        build(1,num,T[0]);
        for(int i=1;i<=n;i++){
            int x=lower_bound(a+1,a+1+num,aa[i])-a;
            update(1,num,T[i],T[i-1],x);
        }
        while(m--){
            int l,r,k;
            scanf("%d%d%d",&l,&r,&k);
            int pos=query(1,num,T[l-1],T[r],k);
            printf("%d\n",a[pos]);
        }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值