poj2104K-th Number

链接:http://poj.org/problem?id=2104

题意:给定一个长度为n的数组,给定q个询问:(l,r,k)求在a[l]~a[r]之间的第k小。

分析:裸的可持久化线段树。

代码:

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=100100;
const int MAX=100000000;
const int mod=100000000;
const int MOD1=1000000007;
const int MOD2=1000000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=998244353;
const ll INF=10000000010;
typedef double db;
typedef unsigned long long ull;
int a[N],b[N],c[N];
int sz,root[N],ls[20*N],rs[20*N],num[20*N];
void add(int l,int r,int x,int &y,int z) {
    y=++sz;num[y]=num[x]+1;
    if (l==r) return ;
    int mid=(l+r)>>1;
    ls[y]=ls[x];rs[y]=rs[x];
    if (z<=mid) add(l,mid,ls[x],ls[y],z);
    else add(mid+1,r,rs[x],rs[y],z);
}
int get_k(int l,int r,int x,int y,int k) {
    if (l==r) return l;
    int mid=(l+r)>>1;
    if (num[ls[y]]-num[ls[x]]>=k) return get_k(l,mid,ls[x],ls[y],k);
    else return get_k(mid+1,r,rs[x],rs[y],k-num[ls[y]]+num[ls[x]]);
}
int main()
{
    int i,k,n,m,w,l,r;
    scanf("%d%d", &n, &m);
    for (i=1;i<=n;i++) {
        scanf("%d", &a[i]);b[i]=a[i];
    }
    sort(b+1,b+n+1);
    k=unique(b+1,b+n+1)-(b+1);
    for (i=1;i<=n;i++) {
        w=lower_bound(b+1,b+k+1,a[i])-b;
        c[w]=a[i];a[i]=w;
    }
    for (i=1;i<=n;i++) add(1,n,root[i-1],root[i],a[i]);
    while (m--) {
        scanf("%d%d%d", &l, &r, &k);
        printf("%d\n", c[get_k(1,n,root[l-1],root[r],k)]);
    }
    return 0;
}


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