C++STL(set……)
set
底層實(shí)現(xiàn)是用紅黑樹。
set 建立
set<int> s; // 不可重,默認(rèn)升序 set<int,less> s; // 不可重,升序 set<int,greater> s; // 不可重,降序 multiset<int> s; // 可重集set 也可以重載,利用結(jié)構(gòu)體實(shí)現(xiàn)。
重載方式同 priority_queue 。
set 插入及訪問
set<int>::iterator it; s.insert(x); // 插入元素 x s.begin(); // 最前面的迭代器 s.end(); // 最后一個(gè)元素之后的迭代器(實(shí)則空) s.rbegin(); // 最后一個(gè)迭代器 s.rend(); // 最前面的前一個(gè)迭代器pair<set<int>::iterator,bool> it=s.insert(x); if(it.second) { 插入成功 } else { 插入失敗 }set 大小
s.size(); //返回容器中元素的數(shù)目 s.empty(); //判斷容器是否為空set 的刪除操作
s.clear(); //清除所有元素 s.erase(it); //刪除 it 迭代器所指的元素,返回下一個(gè)元素的迭代器。 s.erase(l,r); //刪除區(qū)間 [l,r) 的所有元素,返回下一個(gè)元素的迭代器。 s.erase(x); //刪除容器中值為 x 的元素。有的時(shí)候?yàn)榱吮苊鈩h除一個(gè)空的位置,在刪除是可以采用以下操作:
s.erase(s.find(*it));set 的查找操作
s.find(x); //查找 x 元素,返回指向 x 元素的迭代器。 s.count(x); //返回容器中值為 x 的元素個(gè)數(shù)。對(duì) set 來說,要么是 0,要么是 1。對(duì) multiset 來說,值可能大于 1。 s.lower_bound(x); //返回第一個(gè) >=x 元素的迭代器 s.upper_bound(x); // 返回第一個(gè) >x 元素的迭代器。 s.equal_range(x); //返回容器中與 x 相等的上下限的兩個(gè)迭代器。上限是閉區(qū)間,下限是開區(qū)間,如 [l,r) 。例題
P1081 [NOIP2012 提高組] 開車旅行
用 \(\text{set}\) 維護(hù)的部分:
給定數(shù)列 \(\{h\}\) (\(h_i\) 互不相同),定義兩點(diǎn) \(i,j(i<j)\) ,它們間的距離 \(dist(i,j)\) 為 \(abs(h[i]-h[j])\) 。
對(duì)于每個(gè) \(i\) ,求出距離 \(i\) 最近、次近的 \(j(j>i)\) (若距離一致,\(h\) 越小的 \(j\) 距離 \(i\) 更近)。
考慮用 set 與 lower_bound 實(shí)現(xiàn)。
由于最后的幾個(gè)數(shù)找不到相應(yīng)的答案,因此要在 set 中提前加入極大、極小的值。
每次查詢 \(i\) 時(shí),查出比 \(h[i]\) 小的最大編號(hào),再訪問其向前、向后的迭代器即可。
部分代碼 h[0]=inf,h[n+1]=-inf; st.insert((Data){inf,0}),st.insert((Data){inf,0}); st.insert((Data){-inf,n+1}),st.insert((Data){inf,n+1}); for(int i=n;i;i--) {int ga,gb; // ga:max_max gb:max_minst.insert((Data){h[i],i});set<Data>::iterator it=st.lower_bound((Data){h[i],i});it--;int ln=(*it).num,lh=(*it).val;it++,it++;int rn=(*it).num,rh=(*it).val;it--;if(abs(lh-h[i])<=abs(rh-h[i])){gb=ln,it--,it--;if(abs(h[i]-(*it).val)<=abs(rh-h[i])) ga=(*it).num;else ga=rn;}else{gb=rn,it++,it++;if(abs(h[i]-(*it).val)>=abs(lh-h[i])) ga=ln;else ga=(*it).num;}fa[0][i][0]=ga;fa[0][i][1]=gb; }priority_queue
應(yīng)用——對(duì)頂堆
維護(hù)
void tosame(int size_l) {while(qmin.size()<siz_l) qmin.push(qmax.top()),qmax.pop();while(qmin.size()>siz_l) qmax.push(qmin.top()),qmin.pop(); }void check() {while(qmin.top()>qmax.top()){qmin.pop(),qmin.push(y);qmax.pop(),qmax.push(x);} }例題
P3644 [APIO2015]八鄰旁之橋
給出 \(2n\) 個(gè)點(diǎn),我們需要挑 \(1\) 個(gè)點(diǎn),使得這 \(2n\) 個(gè)點(diǎn)到該點(diǎn)的距離和最小。
先考慮 \(k=1\) 的情況,這其實(shí)是一個(gè)很經(jīng)典的結(jié)論,最優(yōu)位置顯然在中位數(shù)處(即排序后第 \(N\) 個(gè)點(diǎn)和第 \(N+1\) 個(gè)點(diǎn)之間的任意一點(diǎn))取得。
接下來是 \(K=2\) 的情況。此時(shí)集合點(diǎn)變成了兩個(gè),畫圖后會(huì)發(fā)現(xiàn),對(duì)于一條線段 \(AB\) 而言,選擇離這個(gè)線段中點(diǎn)較近的集合點(diǎn)結(jié)果最優(yōu)。
考慮將所有線段按 \(s_i+t_i\) 的順序排序,枚舉區(qū)域分界點(diǎn),則分界點(diǎn)左邊的區(qū)域前往左側(cè)集合點(diǎn),右邊的區(qū)域前往右側(cè)集合點(diǎn),問題變成了 \(K=1\) 的情況。
設(shè)集合大小為 \(s\),我們維護(hù)一個(gè)大根堆,存放前 \(\dfrac{s}{2}\) 小的元素,再維護(hù)一個(gè)小根堆,存放后 \(\dfrac{s}{2}\) 小的元素,則中位數(shù)為兩堆的堆頂(任取其一即可)。
代碼
include
reverse 翻轉(zhuǎn)
翻轉(zhuǎn)一個(gè) vector:
reverse(a.begin(),a.end());翻轉(zhuǎn)一個(gè)數(shù)組:
reverse(a+1,a+n+1);unique 去重
unique 用于“去除”容器中相鄰的重復(fù)元素(將重復(fù)的放在容器末尾),并返回去重后的尾地址。
由于去除的是相鄰的元素,一般將容器排好序后去重。
例如:
int a[10]={1,1,2,2,2,3,3,4,5,5}; int ans=unique(a,a+10)-a;則 \(ans\) 的值為 \(5\) 。
vector 去重同理:
int m=unique(a.begin(),a.end())-a.begin();rand_shuffle 隨機(jī)打亂
用法同 reverse ,經(jīng)常在模擬退火與爬山算法中使用。
next_permutation 下一個(gè)排列
若存在下一個(gè)排列,則返回值為 true ,否則為 false 。
lower_bound/upper_bound 二分
指定部分應(yīng)該是排好序的!
lower_bound 返回第一個(gè)大于等于 \(x\) 的元素的迭代器。
upper_bound 第一個(gè)大于 \(x\) 的元素的迭代器。
例如:
查找 int 數(shù)組中大于等于 \(x\) 的最小整數(shù)下標(biāo):
int i=lower_bound(a+1,a+n+1,x)-a;在 vector 中查找小于等于 \(x\) 的最大整數(shù)(假設(shè)存在):
int i=*--upper_bound(a.begin(),a.end(),x);總結(jié)
以上是生活随笔為你收集整理的C++STL(set……)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安卓手机如何清理机身内存
- 下一篇: 内部设计师揭秘!王者峡谷中竟有隐藏的c+