51nod1175區間第k大 小 數(主席樹模板)

2022-06-24 15:30:12 字數 3333 閱讀 8520

分析和思路:

可能最先想到的就是把l,r區間的數拿出來排序後得到答案,但多次頻繁操作時間複雜度太高,這時候強大的資料結構主席樹就發揮出它強大的作用,這就是主席樹模板題目,套模板。

主席樹本質就是線段樹(又稱可持久化線段樹),可以將歷史版本保留下來。對於區間[l, r]的第k大詢問,如果我們能夠得到乙個插入原序列中[1, l - 1]元素的線段樹,和一顆插入了[1, r]元素的線段樹,由於線段樹是開在值域上,區間長度是一定的,所以結構也必然是完全相同的,我們可以直接對這兩顆線段樹進行相減,得到的是相當於插入了區間[l ,r]元素的線段樹。注意這裡利用到的區間相減性質,實際上是用兩顆不同歷史版本的線段樹進行相減:一顆是插入到第l-1個元素的舊樹,一顆是插入到第r元素的新樹。這樣相減之後得到的是相當於只插入了原序列中[l, r]元素的一顆記錄了區間數字個數的線段樹。

插入時,我們顯然不能每次插入乙個元素,就從頭建立一顆全新的線段樹,否則記憶體開銷無法承受。事實上,每次插入乙個新的元素時,我們不需要新建所有的節點,而是只新建增加的節點。也就是從根節點出發,先新建節點並複製原節點的值,然後進行修改即可。

我的天吶,看了這麼長時間總算懂得一點點主席樹了,拿小本本記下來。。

1 #include 2 #include 3 #include 4 #include 5

using

namespace

std;

6const

int maxn=1e5+5;7

int a[maxn],sorted[maxn],root[maxn];//

root每棵樹根存結點

8int

cnt;

9struct

node

10tree[maxn<<5

];13

14int createnode(int su,int ls,int rs)//

建立新樹(先等於原樹)

1522

void update(int l,int r,int &root,int pre_rt,int pos)//

&編號,void&x(原空間)代替了return x返回型更方便更新修改

2331

32int query(int l,int r,int s,int e,int

k)33

41int

main()

4251

52 sort(sorted+1,sorted+1+n);

53 num=unique(sorted+1,sorted+n+1)-(sorted+1);//

num去雜之後的最終範圍

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

55

5960

while(m--)

6171

72return0;

73 }

牛客小白月賽9e:

查詢區間內<=x的數量

思路:本質還是查詢第k小(大),用了lower_bound轉換而已

1 #include 2 #include 3 #include 4 #include 5

using

namespace

std;

6const

int maxn=1e5+5;7

int a[maxn],sorted[maxn],root[maxn];//

root每棵樹根存結點

8int

cnt;

9struct

node

10tree[maxn<<5

];13

14int createnode(int su,int ls,int rs)//

建立新樹(先等於原樹)

1522

void update(int l,int r,int &root,int pre_rt,int pos)//

&編號,void&x(原空間)代替了return x返回型更方便更新修改

2331

32int query(int l,int r,int s,int e,int

k)33

4445

intmain()

4655

56 sort(sorted+1,sorted+1+n);

57 num=unique(sorted+1,sorted+n+1)-(sorted+1);//

num去雜之後的最終範圍

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

59

6364

while(m--)

65//

這個不特判會死迴圈

7374

75int ans=query(1,num,root[x-1

],root[y],t);

76 printf("

%d\n

",ans);77}

7879

return0;

80 }

查詢區間不同數的個數(做法很多,可樹狀陣列,莫隊,主席樹)

sum存的不是第幾大了,而是區間每個不同數的最右邊的位置

1 #include 2 #include 3 #include 4 #include 5

using

namespace

std;

6const

int maxn=1e5+5;7

inta[maxn],sorted[maxn],root[maxn];

8int vis[maxn*10];9

intcnt;

10struct

node

11tree[maxn<<5

];14

15int createnode(int su,int ls,int

rs)16

23void update(int l,int r,int &root,int pre_rt,int pos,int

val)

2432

33int query(int l,int r,int posl,int posr,int

e)34

4546

intmain()

4760

else

6165}66

67 scanf("

%d",&m);

68while(m--)

6977

78int ans=query(1

,n,x,y,root[y]);

79 printf("

%d\n

",ans);80}

8182

return0;

83 }

51Nod 1175 區間中第K大的數

acm模版 遇見這種題,果斷直接套模版,主席樹,也就是可持久化線段樹。這裡需要說一下,由於比較懶,我的模版求得是第 k 小,並且下標是從 0 n 所以呢,我直接在輸出時下標偏移了一,並且對 k 稍加修飾,變成了求第 r l 2 k小的數,效果是一模一樣的,就醬紫。include include in...

51nod 1175 區間中第K大的數

1175 區間中第k大的數 乙個長度為n的整數序列,編號0 n 1。進行q次查詢,查詢編號i至j的所有數中,第k大的數是多少。例如 1 7 6 3 1。i 1,j 3,k 2,對應的數為7 6 3,第2大的數為6。input 第1行 1個數n,表示序列的長度。2 n 50000 第2 n 1行 每行...

51nod1175 區間中第K大的數

裸的主席樹。include include include includeusing namespace std define rep i,s,t for int i s i t i define dwn i,s,t for int i s i t i define clr x,c memset x...