可持久化线段树 区间第k大

Posted xln1111

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了可持久化线段树 区间第k大相关的知识,希望对你有一定的参考价值。

2018-04-04
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1175
一个长度为N的整数序列,编号0 - N - 1。进行Q次查询,查询编号i至j的所有数中,第K大的数是多少。
例如: 1 7 6 3 1。i = 1, j = 3,k = 2,对应的数为7 6 3,第2大的数为6。
 
Input
第1行:1个数N,表示序列的长度。(2 <= N <= 50000)
第2 - N + 1行:每行1个数,对应序列中的元素。(0 <= S[i] <= 10^9)
第N + 2行:1个数Q,表示查询的数量。(2 <= Q <= 50000)
第N + 3 - N + Q + 2行:每行3个数,对应查询的起始编号i和结束编号j,以及k。(0 <= i <= j <= N - 1,1 <= k <= j - i + 1)
Output
共Q行,对应每一个查询区间中第K大的数。
Input示例
5
1
7
6
3
1
3
0 1 1
1 3 2
3 4 2
Output示例
7
6
1

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cctype>
using namespace std;
inline int gi(){int d=0;char c=getchar();while(!isdigit(c))c=getchar();
while(isdigit(c)){d=(d<<3)+(d<<1)+c-0;c=getchar();}return d;}

const int N=50005;
const int M=2000005;
struct QUE{
    int l,r,i,k;
}q[M];
bool cmp1(QUE aa,QUE bb){
    return aa.r<bb.r;
}
int sm[M<<2],ls[M],rs[M],rt[M],tot;
int a[N],san[N],num[N],ans[N],cnt;
int n,Q;
#define gem int mi=(l+r)>>1

void gai(int old,int &o,int l,int r,int P,int C){
    o=++tot;
    ls[o]=ls[old];rs[o]=rs[old];sm[o]=sm[old]+C;
    if(l==r)return;
    gem;
    if(P<=mi)gai(ls[o],ls[o],l,mi,P,C);
    else gai(rs[o],rs[o],mi+1,r,P,C);//??
}
int qur(int old,int o,int l,int r,int k){
    if(l==r)return l;
    int sum=sm[rs[o]]-sm[rs[old]];
    gem;
    if(sum<k)return qur(ls[old],ls[o],l,mi,k-sum);
    else return qur(rs[old],rs[o],mi+1,r,k);
}
#define rep(xx,yy,zz) for(xx=yy;xx<=zz;++xx)
int main(){
    register int i,j;
    n=gi();
    rep(i,1,n){
        a[i]=gi();san[i]=a[i];
    }
    sort(san+1,san+n+1);
    rep(i,1,n)
        if(i==1||san[i]!=san[i-1])
            num[++cnt]=san[i];
    Q=gi();
    rep(i,1,Q){
        q[i].i=i;q[i].l=gi()+1;q[i].r=gi()+1;q[i].k=gi();
    }
    sort(q+1,q+Q+1,cmp1);
    
    j=1;
    rep(i,1,n){
        int x=lower_bound(num+1,num+cnt+1,a[i])-num;
        gai(rt[i-1],rt[i],1,cnt,x,1);
        for(;q[j].r==i;++j){
            ans[q[j].i]=qur(rt[q[j].l-1],rt[i],1,cnt,q[j].k);
        }
    }
    rep(i,1,Q){
        printf("%d\n",num[ans[i]]);
    }
    return 0;
}

 



以上是关于可持久化线段树 区间第k大的主要内容,如果未能解决你的问题,请参考以下文章

可持久化线段树 区间第k大

详解主席树(可持久化线段树)

zoj 2112 Dynamic Rankings 带修改区间第K大 动态主席树

可修改的区间第K大 BZOJ1901 ZOJ2112

luogu3834模板可持久化线段树 2(主席树),静态区间第K小值

区间第K小(可持久化线段树)