2018-7-13 ACM 专项刷题 栈 + 队列 + 树状数组

写的有些久,拖到7-14号凌晨才写完,因为我自己也在慢慢理解中,还是要多做题,做的题越多,理解越深刻。

1. 栈:

stack是一种先进入的元素后弹出的数据结构。

有一种常见的栈的应用就是检查括号匹配与否。

对应题目及题解链接:https://blog.csdn.net/ericgipsy/article/details/79980874

2.队列与优先队列:

    <队列>

queue与stack相反,是一种先进入的元素先弹出的数据结构。

先来一个队列的入门题:

题目:

本人AC代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
const int maxx = 1e3 + 7;
int n, m;
int a[maxx], b[maxx];
int ans;
queue  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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1e4 + 7;
const int Inf = 1e9 + 7;
queue  qua;
map  mp;

priority_queue < int, vector, less > qua1;
priority_queue < int, vector, greater > 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 , less > qua; //降序, 队头大

priority_queue , greater > que; //升序, 队头小

针对 pair 的优先队列,priority_queue qua;默认按照first属性降序排。

对应题目:Codeforces - 994B、Atcoder Beginner 062 - D

Codeforces - 994B 题解链接:https://blog.csdn.net/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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
const ll Inf = 1e17 + 779;
const int maxx = 3e5 + 8;

priority_queue , less > qua; //降序, 队头大
priority_queue , greater > 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 
#include 
#include 
#include 
#include 
#include 
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;
}

你可能感兴趣的:(2018-7-13 ACM 专项刷题 栈 + 队列 + 树状数组)