POJ 2104 主席树板子

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

 

模板题,求区间第k小。  第k大把下面的数字改一下就好啦。 改成num-k+1就好乐!

这里留两个板子吧..0~n-1和1~n的;

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define rep(i,a,b) for(int i = (int)a;i<=(int)b;i++)
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pii;
const int maxn=100005;
int rt[maxn*40],ls[maxn*40],rs[maxn*40],sz[maxn*40];
int tmp[maxn],num,a[maxn],n,q,ct;

int gain(int x){
    return lower_bound(tmp+1,tmp+1+num,x)-tmp;
}
void update(int &now,int las,int l,int r,int pos,int v){
    now=++ct;
    ls[now]=ls[las];
    rs[now]=rs[las];
    sz[now]=sz[las]+v;
    if(l==r) return ;
    int mid=(l+r)/2;
    if(pos<=mid) update(ls[now],ls[las],l,mid,pos,v);
    else update(rs[now],rs[las],mid+1,r,pos,v);
}
int query(int now,int las,int l,int r,int k){
    if(l==r) return l;
    int mid=(l+r)/2;
    int Tmp=sz[ls[now]]-sz[ls[las]];
    if(Tmp>=k) return query(ls[now],ls[las],l,mid,k);
    else return query(rs[now],rs[las],mid+1,r,k-Tmp);
}
int main(){
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        tmp[i]=a[i];
    }
    sort(tmp+1,tmp+1+n);
    num=unique(tmp+1,tmp+1+n)-tmp-1;
    for(int i=1;i<=n;i++){
        update(rt[i],rt[i-1],1,n,gain(a[i]),1);
    }
    while(q--){
        int l,r,k;
        scanf("%d%d%d",&l,&r,&k);
        printf("%d\n",tmp[query(rt[r],rt[l-1],1,n,k)]);
    }
    return 0;
}
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn=1e5+10;
int root[maxn],n,q;
int cnt,a[maxn];
vector<int> v;
struct node{
    int lson,rson,num;
}e[maxn*40];
int gain(int x){
    return lower_bound(v.begin(),v.end(),x)-v.begin();
}
void update(int l,int r,int &now,int pre,int a){
    now=++cnt;
    e[now]=e[pre];
    e[now].num++;
    if(l==r) return ;
    int mid=(l+r)/2;
    if(a<=mid) update(l,mid,e[now].lson,e[pre].lson,a);
    else  update(mid+1,r,e[now].rson,e[pre].rson,a);
}
int query(int l,int r,int now,int pre,int k){
    if(l==r) return l;
    int mid=(l+r)/2;
    int ti=e[e[now].lson].num-e[e[pre].lson].num;
    if(ti>=k) return query(l,mid,e[now].lson,e[pre].lson,k);
    else return query(mid+1,r,e[now].rson,e[pre].rson,k-ti);
}

int main(){
    e[cnt].lson=e[cnt].rson=e[cnt].num=0;
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        v.push_back(a[i]);
    }
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
    for(int i=1;i<=n;i++){
        update(0,n,root[i],root[i-1],gain(a[i]));
    }
    while(q--){
        int l,r,k;
        scanf("%d%d%d",&l,&r,&k);
        printf("%d\n",v[query(0,n,root[r],root[l-1],k)]);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值