1. 程式人生 > 實用技巧 >可持久化線段樹(主席樹) - AcWing - 255 - 第k小數

可持久化線段樹(主席樹) - AcWing - 255 - 第k小數

可持久化線段樹(主席樹) - AcWing - 255 - 第k小數

update 2020-12-28
推薦一種非常好看的寫法良心的可持久化線段樹教程

  1. 本題思路: 對於詢問,利用主席樹處理右端點,利用兩個版本的線段樹作差解決左端點.
  2. 本題程式碼:
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 1e5+50;

int len;
int n,m;
int a,b,c;
int idx;        // 索引分配器
int tree[N<<5];    // 
int lson[N<<5];    // 根索引 -> 左子索引
int rson[N<<5];    // 根索引 -> 右子索引
int roots[N];    // 版本號 -> 根索引
int arr[N]; // 原數列
int newarr[N]; // 有序數列
void build(int l,int r,int &rt){ // 建立空樹
    rt = ++idx;
    if(l==r)return;
    int mid = l+r>>1;
    build(l,mid,lson[rt]);
    build(mid+1,r,rson[rt]);
}


void update(int l,int r,int oldRoot,int &newRoot,int pos){     //單點修改
    newRoot = ++idx;
    tree[newRoot] = tree[oldRoot] + 1;
    if(l == r){
        return;
    }

    int mid = l+r>>1;
    if(pos <= mid){
        rson[newRoot] = rson[oldRoot];
        update(l,mid,lson[oldRoot],lson[newRoot],pos);
    }else{
        lson[newRoot] = lson[oldRoot];
        update(mid+1,r,rson[oldRoot],rson[newRoot],pos);
    }
    // 對於本題,可以不push_up,直接修改 
}   

int query(int l,int r,int lrt,int rrt,int k){ // 傳入 root[l-1], root[r]
    if(l==r)return l;
    int mid = l+r>>1;
    if(k <= tree[lson[rrt]] - tree[lson[lrt]]){
        return query(l,mid,lson[lrt],lson[rrt],k);
    }else{
        return query(mid+1,r,rson[lrt],rson[rrt],k-tree[lson[rrt]]+tree[lson[lrt]]);
    }
}


int main(){
    scanf("%d%d",&n,&m);
    for(int i = 1; i <= n; i++){
        scanf("%d",&arr[i]);
        newarr[i] = arr[i];
    }

    sort(newarr+1,newarr+1+n);
    len = unique(newarr+1,newarr+1+n) - (newarr+1);

    build(1,len,roots[0]);

    for(int i = 1; i <= n; i++){
        int x = lower_bound(newarr+1,newarr+1+len,arr[i]) - newarr;
        update(1,len,roots[i-1],roots[i],x);
    }
    
    for(int i = 1; i <= m; i++){
        scanf("%d%d%d",&a,&b,&c);
        printf("%d\n",newarr[query(1,len,roots[a-1],roots[b],c)]);
    }

    system("pause");
    return 0;
}
  1. 一點感想: 看了清北選手的部落格,感觸挺大. 一方面非常佩服,一方面非常羨慕. 後悔自己從小到大都是玩過來的,只在高三拼了一把,高考還考的挺差. 怪自己. 另外要是原來早點接觸OI就好了呀.感覺這些東西比物理化學那些東西有趣多了. 最後,希望自己能好好提升自己.研究生能上清北吧.