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

最重要的启示:
1.一定要对拍
2.如果错了顶多调3分钟,调不出来赶紧重写
事实证明:重构代码比调试效率高得多!!!
 
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1175
一个长度为N的整数序列,编号0 - N - 1。进行Q次查询,查询编号i至j的所有数中,第K大的数是多少。

https://www.luogu.org/problemnew/show/P3834

洛谷P3834 模板题 第K小

http://codevs.cn/problem/2021/

codevs2021  区间中位数 (也就是第(R-L+2 >>1)小。。)

#include<cstdio>
#include<cstring> 
#include<algorithm>
#include<cctype>
using namespace std;
inline int gi(){
    int d=0,f=1;char c=getchar();while(!isdigit(c)){
        if(c=='-')f=-1;c=getchar();
    }while(isdigit(c)){d=(d<<3)+(d<<1)+c-'0';c=getchar();
    }return d*f;
}
const int N=200005;
const int M=6000005;
int rs[M],ls[M],sm[M],rt[M],tot;
#define gem int mi=(l+r)>>1
void gai(int old,int &o,int l,int r,int P,int C){
    o=++tot;
    sm[o]=sm[old]+C;
    ls[o]=ls[old];rs[o]=rs[old];
    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[ls[o]]-sm[ls[old]];gem;
    if(sum>=k)return qur(ls[old],ls[o],l,mi,k);
    else return qur(rs[old],rs[o],mi+1,r,k-sum);
}
int a[N],san[N],num[N],cnt;
#define rep(xx,yy,zz) for(xx=yy;xx<=zz;++xx)
int ans,n,Q,x,L,R,K;
int main(){
    register int i;
    n=gi();Q=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];
    rep(i,1,n){
        x=lower_bound(num+1,num+cnt+1,a[i])-num;
        gai(rt[i-1],rt[i],1,cnt,x,1);
    }
    rep(i,1,Q){
        L=gi();R=gi();K=(R-L+2)>>1;
        ans=qur(rt[L-1],rt[R],1,cnt,K);
        printf("%d\n",num[ans]);
    }
    return 0;
}

 

 

 



posted @ 2018-04-04 09:29  better?  阅读(552)  评论(0编辑  收藏  举报