最大数maxnumber - 题解【树状数组】

原题:

现在请求你维护一个数列,要求提供以下两种操作:

1、 查询操作。语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值。限制:L不超过当前数列的长度。

2、 插入操作。语法:A n 功能:将n加上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取模,将所得答案插入到数列的末尾。限制:n是非负整数并且在长整范围内。注意:初始时数列是空的,没有一个数。

Input

  第一行两个整数,M和D,其中M表示操作的个数(M <= 200,000),D如上文中所述,满足D在longint内。接下来M行,查询操作或者插入操作。

Output

  对于每一个询问操作,输出一行。该行只有一个数,即序列中最后L个数的最大数。

Sample Input

5 100
A 96
Q 1
A 97
Q 1
Q 2

Sample Output

96
93
96

题解:

这题一看就是建一个线段树来维护区间的题,但是对于一个萌新来说线段树我都没咋搞明白……据说用单调队列也可以做,但是很麻烦,而且我也没有啥思路……在某位大佬的提示下,我去现学了树状数组,可算是把这题给搞过了。关于树状数组,欢迎前往OI Wiki查看

首先,就是树状数组几件套——lowbit操作,找爹,找前段操作。顺带把需要的变量也准备好了。之前吃过很多次变量定义在函数内部导致堆栈爆炸的亏,所以我视题目要求把一些变量扔到了函数外边,做成了全局变量。而且,全局变量默认值都是0,也省得初始化了。(咳咳,其实初始化是个好习惯,之前写多组的时候就吃过初始化的亏,还好这个题是单组emmm)

const int MAX = 2e5 + 5;
ll a[MAX];
ll tree[MAX];

int sz;
int m;
ll d;

inline int lowbit(int &x) {
	return x & (-x);
}
inline int fa(int &x) {
	return x + lowbit(x);
}
inline int pre(int &x) {
	return x - lowbit(x);
}

 然后就是更新 和查询函数怎么写的问题了。题目的要求是把数据插入到数列的末尾,查询的时候返回末L位的最大值,根据这些条件,我发现(其实不是我发现的),每次操作都和数列的末尾有关。正常的更新是从小到大,查询是从大到小,但是这是针对从数列开头来说的,因此在这里更新和查询的遍历方式颠倒一下,更新从大到小,查询从小到大。

void update(ll num) {
	a[++sz] = num;//读入数据,同时更新此时的容量
	for (int i = sz; i > 0; i = pre(i)) {
		tree[i] = max(tree[i], num);
	}
}
ll query(int k) {
	ll maxx = 0;
	for (int i = sz - k + 1; i <= sz; i = fa(i)) {//末尾k个数,寻找的边界索引需要+1
		maxx = max(maxx, tree[i]);
	}
	return maxx;
}

 然后就是普通的AC代码啦。这里其实还有一个小技巧:scanf里面的格式化字符串如果需要读入一个字符(%c)的话,可以在其前面加一个空格,写成" %c %lld"的形式,意思就是说读入的时候忽略%c前面的空白字符,包括空格、回车、制表符以及一些其他的不可见符号。要不然,在输入第一组查询命令后,按下回车,回车符会被下一轮中的%c给吃掉emmm……

#include <bits/stdc++.h>
#define grp int T;cin>>T;while(T--)
#define elif else if
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define rrep(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
typedef long long ll;

const int MAX = 2e5 + 5;
ll a[MAX];
ll tree[MAX];

int sz;
int m;
ll d;

inline int lowbit(int &x) {
	return x & (-x);
}
inline int fa(int &x) {
	return x + lowbit(x);
}
inline int pre(int &x) {
	return x - lowbit(x);
}

void update(ll num) {
	a[++sz] = num;
	for (int i = sz; i > 0; i = pre(i)) {
		tree[i] = max(tree[i], num);
	}
}
ll query(int k) {
	ll maxx = 0;
	for (int i = sz - k + 1; i <= sz; i = fa(i)) {
		maxx = max(maxx, tree[i]);
	}
	return maxx;
}

int main() {

	scanf("%d %lld", &m, &d);
	char q;
	ll n;
	ll t = 0;
	rep(i, 1, m) {
		scanf(" %c %lld", &q, &n);
		if (q == 'Q') {
			t = query(n);
			printf("%lld\n", t);
		}
		elif(q == 'A') {
			update((n + t) % d);
		}
	}

	return 0;
}
上一篇:c语言习题:出现一次的数字


下一篇:类模板学习20210921