POJ-2104_K-th Number(主席树入门)

题目传送门

一篇不错的主席树博客:https://blog.csdn.net/ModestCoder_/article/details/90107874
翻译过来的中文题面

问题描述:
给定一个数组 a[1…n],数组元素各不相同,你的程序要对每次查询Q(i,j,k)作出回答,其中Q(i,j,k)的含义为在数组a[i…j]中第k大的数字.
例如,给出数组a=(1, 5, 2, 6, 3, 7, 4).查询语句为Q(2, 5, 3),即从(5,2,6,3)中找出第3大的元素,将之排序得到(2, 3, 5, 6),故第三大的数字是5,所以这次查询的结果应当为5.
输入格式
数据第1行有两个数字N与M,分别表示数组元素的个数与查询次数(1 <= n <= 100000, 1 <= m <= 5000).
第2行有N个数字,表示数组中的各元素,数组中各元素互不相同,并且每个数字的绝对值不超过109.
接下来的m行,每行包含3个数字i,j,k,(1 <= i <= j <= n, 1 <= k <= j - i + 1),表示一次查询Q(i,j,k)
输出格式
对于每次查询,输出查询结果,即a[i…j]中第k大的数字,每个结果占一行
Sample Input
7 3
1 5 2 6 3 7 4
2 5 3
4 4 1
1 7 3
Sample Output
5
6
3
Hint
输入数据较多,请使用C语言风格的输入输出(scanf(),printf()),否则可能发生Time Limit Exceed.

这道题就是一道很好主席树入门题,也是最简单的主席树查询区间第K小的用法。刚学主席树,用的还不是很熟,目前也就先敲一个板子记录一下,先入个门,之后慢慢来补充吧。
AC

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
//#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int a[N],b[N],lc[N<<5],rc[N<<5],rt[N<<5],sum[N<<5];
int q,js=0,p;
int ans=0;
void build(int &rt,int l,int r)
{
    rt=++js;
    sum[rt]=0;
    if(l==r)return;
    int mid=(l+r)>>1;
    build(lc[rt],l,mid);
    build(rc[rt],mid+1,r);
}
int add(int o,int k,int l,int r)
{
    int oo=++js;
    lc[oo]=lc[o],rc[oo]=rc[o],sum[oo]=sum[o]+1;
    if(l==r)return oo;
    int mid=(l+r)>>1;
    if(mid>=k)
    {
        lc[oo]=add(lc[oo],k,l,mid);
    }
    else
    {
        rc[oo]=add(rc[oo],k,mid+1,r);
    }
    return oo;
}
int slary(int x,int y,int l,int r,int k)
{
     int mid=(l+r)/2;
    ans=sum[lc[y]]-sum[lc[x]];
    if(l==r)return l;
    if(ans>=k)
    {
        return slary(lc[x],lc[y],l,mid,k);
    }
    else
    {
        return slary(rc[x],rc[y],mid+1,r,k-ans);
    }
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        b[i]=a[i];
    }
    sort(b+1,b+1+n);
    q=unique(b+1,b+1+n)-b-1;
    build(rt[0],1,q);
    for(int i=1;i<=n;i++)
    {
        int k=lower_bound(b+1,b+1+q,a[i])-b;
        rt[i]=add(rt[i-1],k,1,q);
    }
    while(m--)
    {
        int l,r,k;
        scanf("%d%d%d",&l,&r,&k);
        printf("%d\n",b[slary(rt[l-1],rt[r],1,q,k)]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43402296/article/details/104298232