HDU2665 Kth number(主席樹入門)

傳送門:http://acm.hdu.edu.cn/showproblem.php?pid=2665
主席樹呢,就是可持久化線段樹,非常神奇。我在B站看了qsc大神的視頻之後就大概懂意思了,先做個入門題,再慢慢學。
打個廣告:http://www.bilibili.com/video/av4619406/
題意是求區間內第k大的數(實際上是k小),主席樹是這樣做的,把n個數離散化之後建一個線段樹,每個葉子節點表示第x大的數分別有幾個,然後pushup上來這個區間內的數字總數。在這個線段樹中如果要求第k大的數很容易,就是找k在左區間還是右區間,在左區間的話,就是繼續找k。在右區間的話,就是k-左區間總數。找到葉子節點之後,這個下標就是第k個數的離散化後的下標。那麼我們對每個前綴建一個線段樹,就是通過主席樹來實現。然後在[l,r]區間求k的話,第r個線段樹-第l-1個線段樹,就是這個區間內的線段樹,然後用上面的思路來找第k個數就可以了。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <ctime>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define calm (l+r)>>1
const int INF=1e9+7;

const int maxn=100000;
int n,m,tot;
int a[maxn+10],rt[maxn+10];
struct node{
    int l,r,sum;
}tree[maxn*20];
vector<int> v;
inline int getid(int x){
    return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
void build(int l,int r,int &x){
    x=++tot;
    tree[x].sum=0;
    if(l==r)return;
    int m=(l+r)>>1;
    build(l,m,tree[x].l);
    build(m+1,r,tree[x].r);
}
void update(int l,int r,int &x,int y,int k){
    x=++tot;tree[x]=tree[y];tree[x].sum++;
    if(l==r){
        return;
    }
    int m=(l+r)>>1;
    if(k<=m)update(l,m,tree[x].l,tree[y].l,k);
    else update(m+1,r,tree[x].r,tree[y].r,k);
}
int query(int l,int r,int x,int y,int k){
    if(l==r)return l;
    int m=(l+r)>>1;
    int sum=tree[tree[y].l].sum-tree[tree[x].l].sum;
    if(k<=sum)return query(l,m,tree[x].l,tree[y].l,k);
    else return query(m+1,r,tree[x].r,tree[y].r,k-sum);
}
int main(){
    //freopen("D://input.txt","r",stdin);
    int T;scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        v.clear();
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            v.pb(a[i]);
        }
        sort(v.begin(),v.end());
        v.erase(unique(v.begin(),v.end()),v.end());
        int cnt=v.size();
        tot=0;build(1,cnt,rt[0]);
        for(int i=1;i<=n;i++){
            update(1,cnt,rt[i],rt[i-1],getid(a[i]));
        }
        while(m--){
            int l,r,x;scanf("%d%d%d",&l,&r,&x);
            printf("%d\n",v[query(1,cnt,rt[l-1],rt[r],x)-1]);
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章