可持久化線段樹(主席樹) 陣列

2021-08-11 20:48:38 字數 1604 閱讀 7577

題目描述

給定n個正整數構成的序列,將對於指定的閉區間查詢其區間內的第k小值。

輸入格式:

第一行包含兩個正整數n、m,分別表示序列的長度和查詢的個數。

第二行包含n個正整數,表示這個序列各項的數字。

接下來m行每行包含三個整數 l, r, kl,r,k , 表示查詢區間[l, r][l,r]內的第k小值。

輸出格式:

輸出包含k行,每行1個正整數,依次表示每一次查詢的結果

輸入輸出樣例

輸入樣例:

5 5

25957 6405 15770 26287 26465

2 2 1

3 4 1

4 5 1

1 2 2

4 4 1

輸出樣例:

6405

15770

26287

25957

26287

好,那麼例題給出,首先我們考慮如果是在乙個區間裡查詢第k小元素,我們完全可以使用線段樹來求解,那麼好了這道題的重點來了,我們如何實現指定區間內的第k小查詢;

我們可以想到如果我們需要查詢【l,r】這一段區間的資訊,我們可以用【1,r】的資訊減去【1,l】的資訊;就可以得到【l,r】的資訊;

但顯然,空間上是不允許我們將從【1,1】到【1,n】的每乙個節點都建一棵線段樹的,但我們可以發現從我們不需要每次都重建一棵線段樹因為線段樹節點資訊很大一部分都是重複的,所以我們如果只記錄發生改變的節點而把其他相同的部分全部保留,這樣的空間複雜度就可以接受了;

具體看**~

【陣列版極醜**】

#include

#include

#include

#include

#include

#include

using

namespace

std;

struct data_ttre[6000005];//線段樹

struct data_ppot[200005];

int n,m,rel[200005],top,t;

bool cmp1(data_p a,data_p b)

int mid=(tre[a].l+tre[a].r)/2;

if(b<=mid)

else

}void change(int a,int b,int c)//遞迴建點 a是原節點,b是新節點,c是要修改的值

else

//新節點在左子樹上

}int find(int a,int b,int c)//查詢

int main()

//離散化

sort(pot+1,pot+n+1,cmp1);

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

sort(pot+1,pot+n+1,cmp2);

for(int i=1;i<=n;i++)//建樹

t=n;

work(1,pot[1].to);

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

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

return

0;}

可持久化線段樹(主席樹)及可持久化陣列

定義 可以訪問歷史版本的線段樹為可持久化線段樹 可持久化線段樹之所以可以訪問歷史版本,是因為巨集觀上看,它為每個版本維護了一棵樹。當然,如果真的對每個版本建一顆樹,時間空間複雜度都hold不住。所以建立i版本的樹時,如果某顆子樹相對於i 1版本沒有變化,就可以直接使其父親對應的指標指向i 1版本的這...

主席樹(可持久化線段樹)

我真弱。連主席樹都不會。主席樹相當於多個線段樹,由於相鄰兩棵線段樹的節點的值只有少許不同,因此可以對於和前一棵樹一樣的子樹乙個指標指過去,無需操作,這樣每棵樹o logn 總複雜度o nlogn 以下是區間k大 include include include define n 100005 defi...

主席樹 可持久化線段樹

首先要學會普通的線段樹,然後理解權值線段樹,而主席樹就是多個權值線段樹 我自己的理解 但是這多個權值線段樹之間有公共部分,節約了空間。它一開始是乙個空樹,後來逐個添數,記錄新增的這個數在那個範圍內,並 1,顯然它每次只更新了一條鏈,其他不需要變,這樣就有了多個版本的線段樹。如果求 l,r 範圍內第k...