写的有些久,拖到7-14号凌晨才写完,因为我自己也在慢慢理解中,还是要多做题,做的题越多,理解越深刻。
1. 栈:
stack是一种先进入的元素后弹出的数据结构。
有一种常见的栈的应用就是检查括号匹配与否。
对应题目及题解链接:https://blog.youkuaiyun.com/ericgipsy/article/details/79980874
2.队列与优先队列:
<队列>
queue与stack相反,是一种先进入的元素先弹出的数据结构。
先来一个队列的入门题:
题目:<Codeforces - 1009A>
本人AC代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <queue>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxx = 1e3 + 7;
int n, m;
int a[maxx], b[maxx];
int ans;
queue <int> qua;
int main() {
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= m; i++) {
cin >> b[i];
qua.push(b[i]);
}
int ans = 0;
for(int i = 1; i <= n; i++) {
if(qua.front() >= a[i] && !qua.empty()) {
ans++;
qua.pop();
}
}
cout << ans << endl;
}
再就是,其中有一种应用就是约瑟夫环,可以理解为一个循环队列:
对应题目链接:https://vjudge.net/problem/OpenJ_Bailian-3254
本人AC代码:
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1e4 + 7;
const int Inf = 1e9 + 7;
queue <int> qua;
map <int, int> mp;
priority_queue < int, vector<int>, less<int> > qua1;
priority_queue < int, vector<int>, greater<int> > qua2;
int main() {
int a, b, c;
while(cin >> a >> b >> c && a && b && c) {
for(int i = b; i <= a; i++) qua.push(i);
for(int i = 1; i < b; i++) qua.push(i);
while(qua.size() > 1) {
for(int i = 0; i < c - 1; i++) {
int tmp = qua.front();
qua.pop();
qua.push(tmp);
}
printf("%d,", qua.front());
qua.pop();
}
printf("%d\n", qua.front());
while(!qua.empty()) qua.pop();
}
}
<优先队列>
优先队列是一种能形成自动排序的队列,分为升序(队头大)和降序(队头小),默认从大到小:
priority_queue <ll, vector<ll>, less<ll> > qua; //降序, 队头大
priority_queue <ll, vector<ll>, greater<ll> > que; //升序, 队头小
针对 pair 的优先队列,priority_queue <pr> qua;默认按照first属性降序排。
对应题目:Codeforces - 994B、Atcoder Beginner 062 - D
Codeforces - 994B 题解链接:https://blog.youkuaiyun.com/ericgipsy/article/details/80729562
Atcoder Beginner 062 - D 题解:
题意:
给定一个长度为3 * n的序列,在其中删除n个元素,问由剩下的2 * n个元素构成的新序列,前一半n个元素的和与后一半n个元素的和差值最大是多少。
思路:
序列分成三段长度为n的子序列,依题可知,肯定是用中间那段长度为n的子序列去替换两边的序列的某些元素,要想差值最大,那就需要将中间那段长度为n的序列内较大的元素尽可能替换左边序列的较小者,同理用中间序列的较小者替换右边序列的较大者。所以声明两个优先队列,一个升序一个降序,将左序列的元素压进升序的优先队列内,右序列压进降序的优先队列内,然后先将中间序列的元素向右推进,维护一个队头,处理出每个位置所能让左序列形成的最大的和,同理从右向左推进处理出每个位置所能让右序列形成的最大的和,然后对于 i 从 n ~ 2 * n,取suml[i] 与sumr[i + 1]所能形成的最大差值即为所求,之所以不是对应位置的两个数组做差,是因为中间序列的每个元素不能重复使用,左右枚举出来的区间必须是无缝对接的。
本人AC代码:
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <queue>
#include <stack>
#include <map>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll Inf = 1e17 + 779;
const int maxx = 3e5 + 8;
priority_queue <ll, vector<ll>, less<ll> > qua; //降序, 队头大
priority_queue <ll, vector<ll>, greater<ll> > que; //升序, 队头小
int n;
ll a[maxx];
ll suml[maxx], sumr[maxx];
ll s1, s2;
int main() {
scanf("%d", &n);
for(int i = 1; i <= n * 3; i++) {
scanf("%lld", &a[i]);
if(i <= n) {
s1 += a[i];
que.push(a[i]);
}
else if(i >= 2 * n + 1) {
s2 += a[i];
qua.push(a[i]);
}
}
suml[n] = s1;
sumr[n * 2 + 1] = s2;
int l = n + 1, r = 2 * n;
while(l <= r) {
if(a[l] > que.top()) {
s1 += a[l];
s1 -= que.top();
que.pop();
que.push(a[l]);
}
suml[l] = s1;
l++;
}
l = n + 1, r = 2 * n;
while(l <= r) {
if(a[r] < qua.top()) {
s2 += a[r];
s2 -= qua.top();
qua.pop();
qua.push(a[r]);
}
sumr[r] = s2;
r--;
}
ll ans = -Inf;
for(int i = n; i <= n * 2; i++) ans = max(ans, suml[i] - sumr[i + 1]);
printf("%lld\n", ans);
}
3.树状数组:
树状数组主要有区间查询和单点更新两个操作,树状数组是一种低级的线段树。
树状数组初始化、区间求和、单点更新 模板:
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxx = 107;
int n;
int a[maxx];
int tree[maxx];
int lowbit(int x) {
return x & (-x);
}
int get_sum(int x) {
int sum = 0;
while(x > 0) {
sum += tree[x];
x -= lowbit(x);
}
return sum;
}
void update(int x, int t) {
while(x <= n) {
tree[x] += t;
x += lowbit(x);
}
}
int main() {
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= n; i++) {
for(int j = i; j > i - lowbit(i); j--) tree[i] += a[j];
}
cout << get_sum(5) << endl;
cout << get_sum(6) - get_sum(2) << endl;
update(1, 1);
cout << get_sum(5) << endl;
cout << get_sum(6) - get_sum(2) << endl;
}