priority_queue
最常用的當然是在dij的時候.
#include <queue>
struct node {
int x, dis;
bool operator < (const node a) const { return a.dis < dis; }
//需要注意的是這個地方要反着寫,一定要反着寫,也就是平常打cmp時的dis<a.dis改成a.dis<dis
//然後在node a前面加上一個const
};
priority_queue<node> Q;
當然,這裏有很多種打法,我現在習慣於用下面這種,不用去記那些什麼const
麻煩:
struct node {
int x, dis;
friend bool operator (node x, node y) { return x.dis < y.dis; }
}
priority_queue <node> Q;
Q.top().x
就是每次堆頂的元素了。
Dijkstra這樣打:
priority_queue <node> Q; Q.push({i, 0}), mem(vis, 0), mem(dis, 7), dis[i] = 0;
while (Q.size()) {
k = Q.top().x; Q.pop();
if (vis[k]) continue; vis[k] = 1;
for (x = las[k] ; x ; x = nex[x])
if (dis[tov[x]] > dis[k] + 1)
dis[tov[x]] = dis[k] + 1, Q.push({tov[x], dis[tov[x]]});
}
雖然priority_queue
沒有set
那麼好用,但畢竟set
存不了實數,所以有時候優先隊列也是略勝一籌的。
它還有這些基本操作:
priority_queue<int> Q; //這樣就定義了一個優先隊列
priority_queue<double> Q; //這樣也可以
priority_queue<node> Q; // 存儲一個結構體,例如像上面的dijkstra時的結構體。
//但如果不用結構體,我們可以這樣子打,在定義的時候確定運算符:
priority_queue<int, vector<int>, less<int> > Q; //這樣是從大到小的,也是C++默認的
priority_queue<int, vector<int>, greater<int> >Q; //這樣是從小到大的
注意 vector<int>
以及後面的> >
不要連起來.
和普通隊列一樣,它有這些基本操作:
q.size();//返回q裏元素個數
q.empty();//返回q是否爲空,空則返回1,否則返回0
q.push(k);//在q的末尾插入k
q.pop();//刪掉q的第一個元素
---這個操作最重要。。。。
q.top();//返回q的第一個元素
bitset
- bitset用來壓位,使複雜度在原來的基礎上除以.
#include <bitset>
bitset<N> S; //這樣就可以建一個bitset了
S.set(); //全部變成1
S.reset(); //全部變成0
S.count(); // 返回1的個數
S.flip(); // 把S每一位都取反
S.flip(i); //僅把第i爲取反
S.any(); //返回是否有1
S.none(); //返回是否沒有1
///表示並不知道這個看似牛逼的操作有什麼用
a.to_ulong() //轉成一個unsigned long long的數.
//bitset支持位運算操作,非常強大.
如 a = a & b; a = a ^ b; a = a | b;
還需要注意的是,bitset支持左移、右移操作,得到一個新的bitset。
具體的,這個操作可以用在一些形如的操作上,詳細見:https://jzoj.net/senior/#main/show/6123 這道題的DP優化。
vector
表示vector是個既能裝逼,又實用的東西,但請注意: vector常數巨大,一般如果是存邊的話,儘量用鄰接表或者前向星.
#include <vector>
vector <int> d,a[N]; //都可以定義
d.push_back(x) //在d這個vector裏面插入一個x元素,注意,相當於數組的插入.
printf("%d", d[i]) //詢問插入的第i個元素,注意下標從0開始
printf("%d", d.size() - 1) //返回插入元素個數
d.front(); d.back(); //第一個,最後一個元素,好吧實際上沒有用
d.clear(); //清空
把d排序:sort(d.begin(), d.end());
struct node {
int u, dis;
bool operaotr < (node x) const { return dis < x.dis; }
}
當然,也可以定義結構體vector<node>,然後按上面的一樣排序就可以了.
d.insert(d.begin() + k, v) // 表示在第k個位置插入一個元素v,把k+1~d.end()的都往後移一個位置.
//表示並不知道上面這個操作有什麼用,並且當k=0時,插入550000個元素,它用了49.007s
//插入100000個元素時,僅用了1.78s
int v = upper_bound(d.begin(), d.end(), node{a, b}) - d.begin() - 1;
//與普通的數組的upper_bound是類似的, 只不過有結構體時,需要operator.
注意,upper_bound是返回第一個大於某數的迭代器
lower_bound是返回第一個大於等於某數的迭代器,這兩個操作很重要,在set裏面也是一樣的.
總結一下,vector裏面這個upper_bound(a.begin(), a.end(), node{x,y}) - a.begin() - 1
這個操作很重要.
然後就是vector雖然方便(比如說打點分樹的時候,需要把每一個分治中心帶的節點用結構體儲存,這時候就超級好用),但是也犧牲了時間,它的常數比較大.
map
map也是一個炒雞好用的STL。據cold_chair大佬所言,當元素很多的時候,map會變得很慢,或者說常數很大…
#include <map>
map<type1, type2> a; //這樣就定義了一個map.
需要注意的是,其中type1表示的是下標的類型,type2則表示的是存儲數的類型.
例如map<string, int> a, map<int, int> a...
修改、使用都是類似於:a[type1] = type2
a.erase(type1) // 表示刪除某個數
a.clear(); //清空
a.empty(); //判斷是否爲空
a.size(); //返回a的元素個數
map的用法還是很多的。
注意,一般來說,我們是定義
map <int, int> h;
如果要在某個位置賦值,可以直接調用
h[x] = y;
但注意,因爲幾乎所有的STL容器我們都只能用
:: iterator it;
來得到位置,所以如果我們要把對應的值求出來,則要用
it -> first 或 it -> seond
兩種操作。
最後還需要知道,map的實現是類似於set的,所以他也支持的查找最小最大值。
具體來說,我們可以這樣調用:
for (map<int,int> :: iterator it = h.begin(); it != h.end(); it ++) {
printf("%d\n",it->first)
H[it->first] = 1;
}
Set
很強大的一個功能。
#include <set>
set <int> a; //這樣就建好一個set了
請務必注意:set是不可以支持重複元素的,想要有重複元素,可以使用multiset
multiset <int> a; //這是可以支持重複元素插入的。
a.insert(x); //表示在set裏面插入一個x元素.
a.erase(x); //表示把set裏面所有爲x的數的刪掉.
a.erase(a.find(x)); //這個表示只刪除一個x.
*a.begin() // 表示最小值
*a.end() // 表示最大值的下一個位置
*--a.end() //表示最大值
// 因爲返回的都是一個迭代器,所以具體數值要在前面加一個*號。
可能有時候要多次用到某個迭代器,所以我們可以把他儲存下來,用一個it來表示,其中it這樣定義:
multiset<int> :: iterator it;
//那麼像上面的最小值,就可以這樣表示it = a.begin(), printf("%d\n", *it).
it ++就可以表示下一個位置的元素,當然不要濫用,因爲這個++是需要log的時間複雜度的。。
其中,set裏面最重要的兩個操作就是上面vector裏面的兩個操作,即lower_bound和upper_bound.
it = a.lower_bound(x) //表示找到第一個大於等於x元素的迭代器
it = a.upper_bound(x) //表示找到第一個大於x元素的迭代器
注意,如果合併兩個map,我們可以用上面的查找 + 對應位置賦值 實現。
但是set可以更方便的寫成:
Set1.insert(Set2.begin(),Set2.end());
這樣就把Set2插入到Set1中去了。
請注意,和都可以用來做啓發式合併,且常數幾乎一模一樣。
ctime
- 測時間的以及隨機時候用的.
srand(time(0)) //隨機種子,沒有這個東西,隨機相當於沒有隨機.
主要想說的是這個:
int st = clock();
// do sth
printf("%lf\n", (double) (clock() - st) / CLOCKS_PER_SEC)
總結
-
wulala~終於把目前所學的一些知識整理了一下.
-
鑑於自己學識淺薄,就不再多逼什麼了.