Basic Data Structure
by PolarisChiba
姓名:李昕威
PolarisChiba
清大準大一生
(方法)
(方法)
(函式)
其實方法在C++中叫做member function
在JAVA中才叫做method
push:複製一個再丟進去
emplace:把數字放進去建構出一個來
vector<pair<int,int>> vec;
vec.push_back(make_pair(1, 2));
vec.emplace_back(1, 2);#include<queue>
using namespace std;
queue<int> q;q.emplace(2);q.front();q.pop();#include<queue>
using namespace std;
queue<int> q;
q.emplace(7122);
q.front();
q.pop();#include<stack>
using namespace std;
stack<int> s;s.emplace(2);s.top();s.pop();#include<stack>
using namespace std;
stack<int> s;
s.emplace(7122);
s.top();
s.pop();(【【】(【】)()】)
給一個括號序列,請問其是否是合法的?
【【】(【】)()】)
(
stack:
【】(【】)()】)
(【
stack:
】(【】)()】)
(【【
stack:
(【】)()】)
(【
stack:
【】)()】)
(【(
stack:
】)()】)
(【(【
stack:
)()】)
(【(
stack:
()】)
(【
stack:
)】)
(【(
stack:
】)
(【
stack:
)
(
stack:
bool check( string line ) {
stack<char, vector<char>> sk;
for (auto x : line) {
if ( x == '(' || x == '[' ) sk.emplace(x);
else if ( x == ')' || x == ']' ) {
if ( sk.empty() ) return false;
char top = s.top();
sk.pop();
if ( top != x ) return false;
}
}
return true;
}#include<deque>
using namespace std;
deque<int> d;d.emplace_front(2);d.pop_front();#include<deque>
using namespace std;
deque<int> d;
d.resize(10);
d.push_back(7122);
d.back();
d.pop_back();
d.push_front(7122);
d.front();
d.pop_front();
d[3] = 7122;7 1 2 2 71 22
(k = 3 為例)
7 1 2 2 71 22
deque:7
7 1 2 2 71 22
deque:7 1
7 1 2 2 71 22
deque:7 2
7 1 2 2 71 22
deque:2 2
7 1 2 2 71 22
deque:71
7 1 2 2 71 22
deque:71 22
vector<int> solve( vector<int> a, size_t k ) {
vector<int> b;
deque<size_t> dq;
for (size_t i = 0, n = a.size(); i < n; ++i) {
while ( !dq.empty && a[i] > a[dq.back()] )
dq.pop_back();
dq.emplace_back(i);
while( dq.front() <= i - k ) dq.pop_front();
// 刪掉不符合的
// 這題先刪、還是後刪過期的都可以
if ( i > k - 2 ) b.emplace_back( a[dq.front()] );
//答案
}
return b;
}
#include<queue>
using namespace std;
priority_queue<int> pq;pq.top();pq.emplace(27);pq.emplace(27);pq.pop();pq.pop();pq.pop();#include<queue>
using namespace std;
priority_queue<int> pq;
pq.emplace(7122);
pq.top();
pq.pop();
if ( mh.empty() || mh.top() > i ) mh.emplace(i);
else Mh.emplace(i);
if (mh.size() > Mh.size() + 1) {
Mh.emplace(mh.top());
mh.pop();
}
if (Mh.size() < mh.size() + 1) {
mh.emplace(Mh.top());
Mh.pop();
}priority_queue<int> pq;
pq.clear(); // Compile Error!Priority Queue挖挖挖
Priority Queue放大鏡
Priority Queue大解密
Stack大解密
Queue大解密
Deque大解密
Stack大解密
stack<int, vector<int>> s;
queue<int, vector<int>> q;
priority_queue<int, vector<int>> pq;stack<int, vector<int>> s;
queue<int, vector<int>> q;
priority_queue<int, vector<int>> pq;
priority_queue<int, vector<int>, less<int>> pq1; // top最大,預設
priority_queue<int, vector<int>, greater<int>> pq2; // top最小#include<set>
using namespace std;
set<int> s;左邊的都比根小
右邊的都比根大
根和根一樣大
set<int> s;s.find(17);s.insert(25);s.erase(17);s.begin();s.rbegin();#include<set>
using namespace std;
set<int> s;
s.insert(7122);
s.begin(); // pointer
*s.rbegin(); // integer
s.end(); // NULL
s.erase(7122);
s.erase(s.begin());
s.erase(s.find(7122));multiset<int> s;set<int, greater<int>> s;bool check(vector<pair<int,int>> &v) {
set<pair<int,int>> s;
for (auto i:v) {
if (i.first == i.second) return false;
s.insert(i);
}
if (v.size() != s.size()) return false;
return true;
}#include<map>
using namespace std;
map<int, string> m;map挖挖挖
m.erase("CSY");m["joylintp"] = 1;m["joylintp"] = -1;#include<map>
using namespace std;
map<string, int> m;
m["CSY"] = 1;
m.erase(m.find("CSY"));
m.begin(); // pointer
*m.rbegin(); // pair
m.begin()->first // string
m.rbegin()->second // intvoid mode(vector<int> &v) {
map<int,int> m;
int ans;
for (auto i:v) {
m[i]++;
if (m[ans] < m[i]) ans = i;
else if (m[ans] == m[i] && ans < i) ans = i;
cout << i << endl;
}
}unordered_map<int, string> m;
unordered_set<int> s;
unordered_multiset<int> ss;int fee(vector<int> &v) {
priority_queue<int, vector<int>, greater<int>> pq;
for (auto i:v) pq.emplace(i);
int ans = 0;
while (pq.size() >= 2) {
int u = pq.top(); pq.pop();
int t = pq.top(); pq.pop();
ans += u + t;
pq.emplace(u + t);
}
return ans;
}void sol(string s) {
vector<int> v;
for (auto i:s) {
if ('0' <= i && i <= '9') v.push_back(i - '0');
else {
int a = v.back(); v.pop_back();
int b = v.back(); v.pop_back();
if (i == '+') v.push_back(a + b);
if (i == '-') v.push_back(a - b);
if (i == '*') v.push_back(a * b);
if (i == '/') v.push_back(a / b);
}
}
return v.back();
}//disjoint set要自己手寫
//因為STL並沒有支援int find(int x) {
if (x == boss[x]) return x;
else return find(boss[x]);
}void unite(int x, int y) {
boss[y] = x;
}此乃線性
啟發式合併(其他技巧會教)
void unite(int x, int y)
{
x = boss[x];
y = boss[y];
if (x == y) return;
if (size[x] < size[y]) swap(x, y);
boss[y] = x;
size[x] += y;
}路徑壓縮
int find(int x) {
if (x == boss[x]) return x;
boss[x] = find(boss[x]);
return boss[x];
}int boss[N], size[N];
int find(int x) {
return x == boss[x] ? x : boss[x] = find(boss[x]);
}
bool same(int x, int y) {
return find(x) == find(y);
}
void unite(int x, int y) {
x = find(x), y = find(y);
if ( same(x, y) ) return;
if ( size[x] < size[y] ) swap(x, y);
boss[y] = x;
size[x] += size[y];
}如果只有朋友的話......
但是這個題目中有敵人...
如果只有朋友的話可以用並查集去維護
那敵人呢?
把朋友丟在黑色圈圈裡
把敵人丟到紫色圈圈裡
同個圈圈中的紫色和黑色是敵人
同個圈圈中的紫色和紫色是朋友
同個圈圈中的黑色和黑色是朋友
不同圈圈間沒什麼關係
紫色圈圈裡的數字可以當作 i + N
int aa = find(a), bb = find(b);
int ra = find(a + N), rb = find(b + N);
//a、b朋友
if (aa == rb) cout << "angry" << endl;
unite(a, b), unite(ra, rb);
// a、b敵人
if (aa == bb) cout << "angry" << endl;
unite(aa, rb), unite(bb, ra);
// a、b朋友嗎?
if (aa == bb) cout << "yeap" << endl;
else cout << "nope" << endl;
//a、b敵人嗎?
if (aa == rb) cout << "yeap" << endl;
else cout <<< "nope" << endl;//Segment Tree要自己手寫
//因為STL並沒有支援int seg[4 * N + 1];
int query(int id, int l, int r, int ql, int qr) {
if (qr < l || r < ql) return 0;
if (ql <= l && r <= qr) return seg[id];
int m = (l + r) / 2;
int v1 = query(id * 2, l, m, ql, qr);
int v2 = query(id * 2 + 1, m + 1, r, ql, qr);
return v1 + v2;
}void update(int id, int l, int r, int i, int v) {
if (l == r) {
seg[id] += v;
return;
}
int m = (l + r) / 2;
if (i <= m) update(id * 2, l, m, i, v);
else update(id * 2 + 1, m + 1, r, i, v);
seg[id] = seg[id * 2] + seg[id * 2 + 1];
}tag[4 * N + 1];void push(int id, int l, int r) {
tag[id * 2] = tag[id];
tag[id * 2 + 1] = tag[id];
seg[id] = tag[id] * (r - l + 1);
tag[id] = 0;
}void update(int id, int l, int r, int ql, int qr, int x) {
push(id, l, r);
if (r < ql || qr < l) return;
if (ql <= l && r <= qr) {
tag[id] = x;
push(id, l, r);
return;
}
int m = (l + r) / 2;
update(id * 2, l, m, ql, qr, x);
update(id * 2 + 1, m + 1, r, ql, qr, x);
seg[id] = seg[id * 2] + seg[id * 2 + 1];
}int query(int id, int l, int r, int ql, int qr) {
push(id, l, r);
if (qr < l || r < ql) return 0;
if (ql <= l && r <= qr) return seg[id];
int m = (l + r) / 2;
int v1 = query(id * 2, l, m, ql, qr);
int v2 = query(id * 2 + 1, m + 1, r, ql, qr);
return v1 + v2;
}void push(int id, int l, int r) {
tag[id * 2] += tag[id];
tag[id * 2 + 1] += tag[id];
seg[id] += tag[id] * (r - l + 1);
tag[id] = 0;
}void update(int id, int l, int r, int ql, int qr, int x) {
push(id);
if (r < ql || qr < l) return;
if (ql <= l && r <= qr) {
tag[id] += x;
push(id);
return;
}
int m = (l + r) / 2;
update(id * 2, l, m, ql, qr, x);
update(id * 2 + 1, m + 1, r, ql, qr, x);
seg[id] = seg[id * 2] + seg[id * 2 + 1];
}void push(int id) {
tag[id * 2] = tag[id];
tag[id * 2 + 1] = tag[id];
seg[id] = tag[id];
tag[id] = 0;
}int query(int id, int l, int r, int ql, int qr) {
push(id);
if (qr < l || r < ql) return 0;
if (ql <= l && r <= qr) return seg[id];
int m = (l + r) / 2;
int v1 = query(id * 2, l, m, ql, qr);
int v2 = query(id * 2 + 1, m + 1, r, ql, qr);
return max(v1, v2);
}void update(int id, int l, int r, int ql, int qr, int x) {
push(id);
if (r < ql || qr < l) return;
if (ql <= l && r <= qr) {
tag[id] = x;
push(id);
return;
}
int m = (l + r) / 2;
update(id * 2, l, m, ql, qr, x);
update(id * 2 + 1, m + 1, r, ql, qr, x);
seg[id] = max( seg[id * 2], seg[id * 2 + 1] );
}//Binary Indexed Tree要自己手寫
//因為STL並沒有支援1:0001
2:0010
3:0011
4:0100
5:0101
6:0110
7:0111
8:1000
2,5,1,4,7,10,2,6
2,12,1,4,7,10,2,6
int bit[N];
void update(int i, int x) {
while (i <= N) {
bit[i] += x;
i += i & -i;
}
}1:0001:0001
2:0010:0010
3:0011:0001
4:0100:0100
5:0101:0001
6:0110:0010
7:0111:0001
8:1000:1000
二進位制,最小的一個 1-bit 的值
2,12,1,4,7,10,2,6
int query(int i) {
int res = 0;
while (i > 0) {
res += bit[i];
i -= i & -i;
}
return res;
}把第二格改成12
2,5,1,4,7,10,2,6
等價於把第二格加上7
2,12,1,4,7,10,2,6
給定一個數列,求有多少個(i, j)數對滿足:
//cnt[i]紀錄1~i總共出現在s中幾次
for(auto i:s) {
ans += cnt[i - 1] - query(i - 1);
update(i, 1);
}
cout << ans << '\n';有可能會有重複的元素
有可能會超出int範圍
有可能有負數
int r, c, bit[N][N];
void update(int x, int y, int v) {
while (x <= r) {
int t = y;
while (y <= c) {
bit[x][y] += v;
y += y & -y;
}
y = t;
x += x & -x;
}
}int query(int x, int y) {
int res = 0;
while (x > 0) {
int t = y;
while (y > 0) {
res += bit[x][y];
y -= y & -y;
}
y = t;
x -= x & -x;
}
return res;
}前提是對面不會動
//Sparse Table要自己手寫
//因為STL並沒有支援int n, s[LOGN][N];
for(int j = 1; (1 << j) <= n; j++)
for(int i = 0; i + (1 << j) <= n; i++)
s[j][i] = min(
s[j - 1][i],
s[j - 1][i + (1 << (j - 1) )]
);
int query(int l,int r) {
int k = __lg(r - l + 1);
return max( s[k][l], s[k][r - (1 << k) + 1] );
}int s1[2500000], n, m;
int l[1000006], r[1000006];
bitset<1000006> ok;
int main(){
scanf("%d %d",&n, &m);
for(int i = 0 ; i < m ; i++)
scanf("%d %d", &l[i], &r[i]), l[i]--, --r[i];
for(int i = 0 ; i < n ; i++) scanf("%d", &s1[i]);
for(int i = 0 ; i < m ; i++)
if( lo(l[i], r[i]) == 0 )
l[i] = s1[ l[i] ], ok[i] = 1;
for(int i = 1; (1 << i) <= n ; i++){
for(int j = 0 ; j + (1 << i) <= n ; j++)
s1[j] = max( s1[j], s1[ j + ( 1 << (i - 1) ) ] );
for(int j = 0 ; j < m ; j++)
if( lo( l[j], r[j] ) == i && !ok[j] )
l[j] = max(
s1[ l[j] ],
s1[ r[j] - ( 1 << i ) + 1 ] ), ok[j] = 1;
}
for(int i = 0 ; i < m ; i++) printf("%d\n", l[i]);
}有三種動物A, B, C,A會吃B、B會吃C、C會吃A
現在有N隻動物,分別屬於ABC其中一種,並有人給你許多它們之間的關係
但這個人有可能說謊,只要滿足以下就算這個人說謊
請問這個人說了多少謊?
可愛小動物的三種關係的版本
詳細實作就請大家參考可愛小動物那一題
在一張N X M的棋盤上,有些地方有地雷,一個地雷被引爆的話會炸到周圍3 X 3的區域;若兩個地雷的3 X 3區域有重疊的話,引爆其中一個的話另一個也會被連鎖引爆。
請問要人工引爆多少個地雷才能炸掉所有地雷?
from TIOJ
for (int t = 0; t < v.size(); ++t)
{
pair<int,int> i = v[t];
for(int dx = -2; dx <= 2; ++dx) for(int dy = -2; dy <= 2; ++dy)
{
int x = i.first + dx, y = i.second + dy;
int d = lower_bound(all(v), make_pair(x,y)) - v.begin();
if(v[d] != make_pair(x,y)) continue;
d = find(d);
int dd = find(t);
if(dd != d) fa[d] = dd, ++cnt;
}
}
cout << n - cnt << endl;第二個問題的答案是DP,就當作早上的課的練習請大家想想囉
看到區間和,有個小技巧是換成前綴和來思考
區間和為正
等價於前綴和相減為正
等價於後面的前綴和比前面的前綴和大
計算多少個後面的元素比前面的大可以用BIT
for (int i = 1; i <= n; ++i) {
ans += (s[i] > 0);
\\離散化
s[i] = lower_bound(all(li), s[i]) - li.begin() + 1;
add(s[i], 1);
ans += sum(s[i] - 1);
}
cout << ans << endl;pair<int,int> a[N];
set<int> s;
bool check(int mid)
{
int res = k;
s.clear(); // 儲存線段在數線上的資訊
for (int i = 0; i < n; ++i) {
while(s.size() && *s.begin() <= a[i].first)
s.erase(s.begin()); // 過期了
s.insert(a[i].second);
while(s.size() > mid) { //現在這個點被太多線段覆蓋
s.erase((--s.end())); // 刪掉右界最右邊的
--res; //我只能刪掉K個區間
}
if(res < 0) return false;
}
return true;
}int flag[4 * N + 1];
int count[4 * N + 1];void pull(int id, int l, int r) {
if ( flag[id] > 0 )
count[id] = r - l + 1;
else count[id] =
count[id * 2] + count[id * 2 + 1];
}int query() {
return count[1];
}void update(int id, int l, int r, int ql, int qr, int v) {
if (qr < l || r < ql) return;
if (ql <= l && r <= qr) {
flag[id] += v;
}
else {
int m = (l + r) / 2;
update(id * 2, l, m, ql, qr, v);
update(id * 2 + 1, m + 1, r, ql, qr, v);
}
pull(id, l, r);
}如果,生命的腳印終有一天
會被時間的塵埃掩埋... ...
那我們就永遠不能
--停下腳步