分析和思路:
可能最先想到的就是把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 5using
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 5using
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 5using
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...