指標主席樹簡單介紹 第k小數

2022-06-17 21:36:11 字數 2539 閱讀 3698

題面簡介:給乙個長度為n(\(n<=2e5\))陣列序列(\(|ai|<=1e9\)),有m(\(m<=2e5\))次查詢,每次查詢區間\([l,r]\)中第k小的數。

還是指標香,雖然常數大了一點,但實現起來速度能快不少

前置知識:知道陣列主席樹的寫法,或者差不多知道主席樹的原理。需要會一點指標。

主席樹,即可持久化線段樹,可以記錄線段樹的多個歷史版本,來達到快速查詢歷史資訊的資料結構。

在第k小數中,以給定陣列中每個數字下標建立更新權值線段樹,如果不使用主席樹進行更新並記錄歷史版本的話,空間將會是n*size(tree)的,即n棵大小為size(tree)的線段樹。

主席樹大幅減少了建立的節點數,每個版本通過新建一整條分支,分支上的節點和之前的版本共用沒有更新的節點,解決了重複的節點建立。

函式詳解:

struct tree 

};//開記憶體池

tree* root[maxn];

tree* pool = (tree*)malloc(sizeof(tree) * (21 * maxn));

tree* cnt = pool;

首先是主席樹節點。指標實現的常數大,寫法較陣列寫法簡單一些,用malloc開記憶體池比動態開點優化了一些記憶體和時間。

tree* build(int l, int r)

然後是build函式,將區間分治並構造出線段樹,當l==r時返回節點指標。由於節點中沒有儲存其所包含的區間,所以在之後的查詢中需要推算得到l和r。

tree* insert(tree*& p, int l, int r, int x)

int mid = l + r >> 1;

if (x <= mid)q->ls = insert(p->ls, l, mid, x);//x<=mid,說明需要往左區間更新,右節點代表的右區間不需要更新

else q->rs = insert(p->rs, mid + 1, r, x);//反之亦然

q->cnt = q->ls->cnt + q->rs->cnt;//傳遞更新結果

return q;//返回節點指標

}

insert應該算是主席樹的核心**,其作用是插入更新結果,並記錄歷史版本

int query(tree*& q, tree*& p, int l, int r, int k)//歷史版本q和歷史版本p,這裡查詢的是區間(l,r),所以歷史版本為l-1和r,然後把2個版本作差

query注釋比較詳細,需要注意的是每次的cnt都是左兒子的cnt之差

#include#include#define ll long long

#define fastio ios::sync_with_stdio(false);cin.tie(null);cout.tie(null);

using namespace std;

double pi = acos(-1);

const double eps = 1e-6;

const int maxn = 2e5 + 10;

const ll inf = llong_max;

unordered_mapid;

int n, m;

struct tree

};//開記憶體池

tree* root[maxn];

tree* pool = (tree*)malloc(sizeof(tree) * (21 * maxn));

tree* cnt = pool;

int a[maxn];

tree* build(int l, int r)

tree* insert(tree*& p, int l, int r, int x)

int mid = l + r >> 1;

if (x <= mid)q->ls = insert(p->ls, l, mid, x);

else q->rs = insert(p->rs, mid + 1, r, x);

q->cnt = q->ls->cnt + q->rs->cnt;

return q;

}int query(tree*& q, tree*& p, int l, int r, int k)

int main()

sort(num.begin(), num.end());

num.erase(unique(num.begin(), num.end()), num.end());

for (int i = 0; i < num.size(); i++)

id[num[i]] = i;

root[0] = build(0, num.size() - 1);

for (int i = 1; i <= n; i++)

root[i] = insert(root[i - 1], 0, num.size() - 1, id[a[i]]);

while (m--)

return 0;

}

主席樹 指標實現 找第k小數

主席樹,其實就是n顆線段樹 只是他們公用了一部分節點 我大部分的 是從一位大佬的那裡看到的 我這個垃圾程式連poj2104上的資料都過不了tle so希望神犇能給我看看,順便給和我一樣的底層人物一點指標的幫助 也許是 new 太慢了 include include include define n ...

區間第k大(主席樹)

學了一下主席樹模板題,當初看了網上的主席樹講解都沒有看懂,後面看了嗶哩嗶哩的uestc的主席樹,終於看懂了思想。每次更新的複雜度都為logn。每次更新的話就是對要更新的點路徑上的點重新更加乙個,然後進行對沒有影響的那些進行連邊。然後用乙個root記錄每乙個線段樹的根節點下標。include incl...

主席樹(區間第k小)

k th number 求區間內第k小的數。主席樹的板子題 主席樹左子樹存小值,右邊大值,用sum記錄一下子樹節點個數。對 l,r 的查詢區間,root r root l 1 可得出 l,r 的差值,也就是大小的個數 include include include include include i...