# 2023 南 11 校聯合寒訓 - STL容器題解
:::warning
**Slide 講義**
link : https://slides.com/jasonliu424/cpp-stl/
:::
:::info
**有地方沒講清楚歡迎來問我 > <**
Github ⚙️ https://github.com/jason810496
FB 🧬 https://www.facebook.com/JasonBigCow
IG 🐮 https://www.instagram.com/jason2004424/
:::
:::success
**延伸閱讀**
非常建議把 **CSES** 的 **Searching & Sorting** 都寫一遍
link : https://cses.fi/problemset/list/
裡面有很多**資料結構**( `STL` `pbds` `BIT` )與**排序、搜尋**搭配的經典技巧!
近幾次的 **APCS 第四題**都跟延伸閱讀的題單蠻相似的!
:::
## vector
### Zerojuege : f819 圖書館
link : https://zerojudge.tw/ShowProblem?problemid=f819
:::spoiler solution
```cpp=
#include<iostream>
#include<vector>
#include<algorithm>
#include<utility>
#define ll long long
#define OAO cin.tie(0);ios_base::sync_with_stdio(0);
#define F first
#define S second
#define PB push_back
#define all(x) x.begin(),x.end()
using namespace std;
signed main(){
OAO
int n;
cin>>n;
int ans=0;
vector<int> over;
int id,d;
while(n--){
cin>>id>>d;
if( d>100 ){
over.push_back(id);
ans+=5*(d-100);
}
}
sort(all(over));
for(const auto & i : over ){
cout<<i<<' ';
}
cout<<(over.empty() ? "":"\n")<<ans<<"\n";
return 0;
}
```
:::
### TOJ : 575
link : https://toj.tfcis.org/oj/pro/575/
:::info
**要注意輸出格式:** 行尾不要有空白
:::
:::spoiler solution
```cpp=
#include<iostream>
#include<vector>
#include<algorithm>
#include<utility>
#define ll long long
#define OAO cin.tie(0);ios_base::sync_with_stdio(0);
#define F first
#define S second
#define PB push_back
#define all(x) x.begin(),x.end()
using namespace std;
vector<int> vec[1000005];
signed main(){
OAO
int n,k;
cin>>n>>k;
while(k--){
int a,b;
cin>>a>>b;
vec[a].push_back(b);
vec[b].push_back(a);
}
for(int i = 1; i <= n; i++){
sort(vec[i].begin(),vec[i].end());
if( vec[i].size() )cout << vec[i][0];
for(int j = 1; j < vec[i].size(); j++){
cout << ' ' << vec[i][j];
}
cout << '\n';
}
return 0;
}
```
:::
## pair
### Zerojuege : a915 二維點排序
link : https://zerojudge.tw/ShowProblem?problemid=a915
:::spoiler solution
用 `pair` 的話:連 `struct` , `compare function` 都不用寫!
```cpp=
#include<iostream>
#include<vector>
#include<algorithm>
#include<utility>
#define ll long long
#define OAO cin.tie(0);ios_base::sync_with_stdio(0);
#define F first
#define S second
#define PB push_back
#define all(x) x.begin(),x.end()
using namespace std;
typedef pair<int,int> pii;
signed main(){
OAO
int n;
cin>>n;
vector<pii> vec(n);
for(auto & i :vec ){
cin>>i.F>>i.S;
}
sort(all(vec));
for(const auto & i : vec ){
cout<<i.F<<' '<<i.S<<'\n';
}
return 0;
}
```
:::
## stack
### Zerojuege : b304 Parentheses Balance
link : https://zerojudge.tw/ShowProblem?problemid=b304
:::info
**輸入格式:** 要用 `getline` 讀
**其他:** 空字串也算正確
:::
:::spoiler solution
```cpp=
#include<iostream>
#include<vector>
#include<algorithm>
#include<utility>
#include<stack>
#include<string>
#define ll long long
#define OAO cin.tie(0);ios_base::sync_with_stdio(0);
#define F first
#define S second
#define PB push_back
#define all(x) x.begin(),x.end()
using namespace std;
signed main(){
OAO
int n;
cin>>n;
string str;
getline(cin,str);
while(n--){
getline(cin,str);
if(str.empty()){
cout<<"Yes\n";
continue;
}
else if( str.size()%2 ){
cout<<"No\n";
continue;
}
stack<char> stk;
bool flag = true;
for(int i=0;i<str.size() && flag ;i++){
if( str[i] == '(' || str[i] == '[' ){
stk.push(str[i]);
}
else if( str[i] == ')' ){
if( stk.empty() || stk.size() && stk.top() != '(' ){
flag = false;
break;
}
else stk.pop();
}
else if( str[i] == ']' ){
if( stk.empty() || stk.size() && stk.top() != '[' ){
flag = false;
break;
}
else stk.pop();
}
}
cout<<(flag&&stk.empty() ? "Yes\n": "No\n" );
}
return 0;
}
```
:::
## deque
### Zerojuege : i400 字串解碼
link : https://zerojudge.tw/ShowProblem?problemid=i400
:::info
題目頗長,要仔細看,解碼要記得反著做
:::
:::spoiler solution
```cpp=
#include<iostream>
#include<vector>
#include<algorithm>
#include<utility>
#include<deque>
#define ll long long
#define OAO cin.tie(0);ios_base::sync_with_stdio(0);
#define F first
#define S second
#define PB push_back
#define all(x) x.begin(),x.end()
using namespace std;
signed main(){
OAO
int m , n;
cin>>m>>n;
vector<deque<int>> decode(m);
deque<char> orig;
string str;
for(auto & i : decode ){
cin>>str;
for(char c : str){
i.push_back( c-'0' );
}
}
cin>>str;
for(char c : str){
orig.push_back( c );
}
int mid=n/2;
for(int k=m-1;k>=0;k--){
// decode part
deque<char> after;
for(int i=n-1;i>=0;i--){
if(decode[k][i]){
after.push_back( orig.back() );
orig.pop_back();
}
else{
after.push_front( orig.back() );
orig.pop_back();
}
}
orig = after;
// swap front & back
int cnt=0;
for(int i=0;i<n;i++){
cnt+=decode[k][i];
}
if( cnt%2 ){
for(int i=0;i<mid;i++){
swap(orig[i],orig[i+mid+(n%2)]);
}
}
}
for(const char & i : orig ){
cout<<i;
}
cout<<'\n';
return 0;
}
```
:::
## set
### CSES : Distinct Numbers
link : https://cses.fi/problemset/task/1621
:::spoiler solution
```cpp=
#include<iostream>
#include<utility>
#include<vector>
#include<set>
using namespace std;
#define OAO cin.tie(0);ios_base::sync_with_stdio(0);
#define F first
#define S second
#define PB push_back
#define all(x) x.begin(),x.end()
signed main(){
OAO
int n,x;
set<int> Uset;
cin>>n;
while( n-- ){
cin>>x;
Uset.insert(x);
}
cout<<Uset.size()<<"\n";
return 0;
}
```
:::
### Zerojuege : f607 切割費用
link : https://zerojudge.tw/ShowProblem?problemid=f607
:::info
:::spoiler 一些提示
1. 考慮邊界條件
2. 會用到 `二分搜` 跟 `iterator`
:::
:::spoiler solution
```cpp=
#include<iostream>
#include<vector>
#include<algorithm>
#include<utility>
#include<set>
#define ll long long
#define OAO cin.tie(0);ios_base::sync_with_stdio(0);
#define F first
#define S second
#define PB push_back
#define all(x) x.begin(),x.end()
using namespace std;
signed main(){
OAO
ll sum=0;
int n,len,tmp,idx;
cin>>n>>len;
set<int> S{0,len};
vector<int> vec(n);
for(int i=0;i<n;i++){
cin>>tmp>>idx;
vec[idx-1]=tmp;
}
set<int>::iterator L,R;
for(int i=0;i<n;i++){
S.insert(vec[i]);
L=S.lower_bound(vec[i]);
L--;
R=S.upper_bound(vec[i]);
sum+=(*R-*L);
}
cout<<sum;
return 0;
}
```
:::
## map
### CSES : Sum of Two Values
link : https://cses.fi/problemset/task/1640
:::spoiler solution
```cpp=
#include<iostream>
#include<vector>
#include<algorithm>
#include<utility>
#include<map>
#define OAO cin.tie(0);ios_base::sync_with_stdio(0);
#define F first
#define S second
#define PB push_back
#define all(x) x.begin(),x.end()
using namespace std;
signed main(){
OAO
int n , k;
cin>>n>>k;
vi arr(n);
map<int,int> MP;
for(int &i: arr) cin>>i;
bool flag = false;
for(int i=0;i<n;i++ ){
int target = k-arr[i];
if( MP.find(target)!=MP.end() ){
cout<<MP[ target ]+1<<" "<<i+1<<"\n";
flag = true;
break;
}
MP[ arr[i] ]=i;
}
if( !flag ) cout<<"IMPOSSIBLE\n";
return 0;
}
```
:::
## priority_queue
### Leetcode : kth largest element in an array
link : https://leetcode.com/problems/kth-largest-element-in-an-array/
:::info
嘗試用 $O( n \log k )$ 的時間複雜度來解
:::
:::spoiler solution
```cpp=
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
priority_queue<int,vector<int>,greater<int>> pq;
for(const int & i : nums ){
pq.push(i);
if(pq.size()>k) pq.pop();
}
return pq.top();
}
};
```
:::
### CSES : Sliding Median
link : https://cses.fi/problemset/task/1076
:::info
這題預設用 `priority_queue` 解,不過也可以用 `multiset` ( 其實後者應該比較好想怎麼解XD )
還有 `pbds` 跟 `binary index tree` 也可以解
:::spoiler 一些提示( 用 PQ 的話 )
1. 中位數可以看成: 前半序列的最大值 or 後半序列的最小值
2. 所以可以開 maxHeap 跟 minHeap 來維護
3. PQ 只能刪除最大或最小值,但是有可能現在在 PQ 中的元素已經不在 window 當中了
4. 承 `3.` 所以需要另一個資料結構來紀錄「哪些元素已經不在 window 中 」這個狀態
5. 需要維護兩個 PQ 的平衡性
:::
:::spoiler solution
```cpp=
#include<iostream>
#include<vector>
#include<algorithm>
#include<utility>
#include<queue>
#include<map>
#define ll long long
#define OAO cin.tie(0);ios_base::sync_with_stdio(0);
#define F first
#define S second
#define PB push_back
#define all(x) x.begin(),x.end()
using namespace std;
typedef pair<int,int> pii;
const int MAX_N = 2e5+5;
int arr[MAX_N];
signed main(){
OAO
int n,k;
cin>>n>>k;
map<int,int> Delete;
priority_queue<int> Left;
priority_queue<int,vector<int>,greater<int>> Right;
for(int i=0;i<n;i++){
cin>>arr[i];
}
int mid=(k+1)/2;
int x;
for(int i=0;i<k;i++){
Right.push(arr[i]);
}
for(int i=0;i<mid;i++){
Left.push(Right.top());
Right.pop();
}
cout<<Left.top()<<" ";
for(int i=k;i<n;i++){
int balance = 0;
int old = arr[i-k];
// delete old element from window
if( old<=Left.top() ){
balance--;
if( old==Left.top() ) Left.pop();
else Delete[ old ]++;
}
else{
balance++;
if( old==Right.top() ) Right.pop();
else Delete[ old ]++;
}
// insert cur into pq
if( arr[i] <= Left.top() ){
balance++;
Left.push(arr[i]);
}
else{
balance--;
Right.push(arr[i]);
}
// balance two pq
if(balance<0) {
Left.push(Right.top());
Right.pop();
}
if(balance>0) {
Right.push(Left.top());
Left.pop();
}
while( Right.size() && Delete[Right.top()]) {
Delete[Right.top()]--;
Right.pop();
}
while( Left.size() && Delete[Left.top()]) {
Delete[Left.top()]--;
Left.pop();
}
cout<<Left.top()<<' ';
}
return 0;
}
```
:::
:::success
如果想知道題怎麼用其他資料結構來解的話:
可以看 [這邊](https://usaco.guide/problems/cses-1076-sliding-median/solution)
:::
###### tags: `題解` `資料結構` `競程`