可持久化線段樹(主席樹) - AcWing - 255 - 第k小數
阿新 • • 發佈:2020-12-28
可持久化線段樹(主席樹) - AcWing - 255 - 第k小數
update 2020-12-28
推薦一種非常好看的寫法良心的可持久化線段樹教程
- 本題思路: 對於詢問,利用主席樹處理右端點,利用兩個版本的線段樹作差解決左端點.
- 本題程式碼:
#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; }
- 一點感想: 看了清北選手的部落格,感觸挺大. 一方面非常佩服,一方面非常羨慕. 後悔自己從小到大都是玩過來的,只在高三拼了一把,高考還考的挺差. 怪自己. 另外要是原來早點接觸OI就好了呀.感覺這些東西比物理化學那些東西有趣多了. 最後,希望自己能好好提升自己.研究生能上清北吧.