[JSOI2008]最大数MAXNUMBER

[JSOI2008]最大数MAXNUMBER

https://ac.nowcoder.com/acm/problem/20164

思路一: 直接上线段树,这个没什么好讲的,线段树最基本的操作

思路二: 单调栈+二分 这里上单调栈是一个很妙的地方,我们可以始终维护出一个线型递减的关系alt

二分即二分我们的目标区间左端在那个区间里,返回区间的右界就好

思路三: 单调栈+并查集 这里的并查集使用又是在二分上的一个优化,同样是用单调栈先维护出来分段的区间 但是在单调栈维护区间的同时,对每个节点的父亲进行维护alt

这样就可以完美的以o(n)的复杂度完成

整个思路很妙的在于(只是我之前每学习过罢了),用数组来模拟栈这个做法,一个数组来作存放元素的栈,一个数组来作存放下标的栈,这样就可以完美解决不方便直接访问栈内元素的问题。

附一个思路二代码:

using namespace std;
int m, d, w, l_ans, cnt, top;
inline int read() {
	int x = 0, f = 1;
	char c = getchar();
	while (c < '0' || c>'9') { if (c == '-') f = -1; c = getchar(); }
	while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
	return x * f;
}
const int N= 200005;
int que[2][N];
void add(int jk) {
	cnt++;
	while (top > 0 && jk > que[0][top]) {
		que[0][top] = 0;
		que[1][top--] = 0;
	}
	
	que[0][++top] = jk;
	que[1][top] = cnt;
}
int query(int jk, int l, int r) {
	while (l < r) {
		int mid = (l + r) / 2;
		if (jk > que[1][mid])
			l = mid + 1;
		else r = mid;
	 }
	return que[0][r];
}

int main() {
	m = read(); d = read();
	
	while (m--) {
		char flag=getchar();
		while (flag != 'A' && flag != 'Q') flag = getchar();
		if (flag == 'A')
			add((read() + l_ans) % d);
		else {
			l_ans = query(cnt - read() + 1, 1, top);
			cout << l_ans << endl;
		}
	}

	return 0;
}



全部评论

相关推荐

不愿透露姓名的神秘牛友
06-11 13:34
offe从四面八方来:我真的没时间陪你闹了
点赞 评论 收藏
分享
程序员小白条:找的太晚,别人都是大三实习,然后大四秋招春招的,你大四下了才去实习,晚1年
点赞 评论 收藏
分享
不愿透露姓名的神秘牛友
07-02 15:39
希望奇迹发生的布莱克...:真的是 现在卷实习就是没苦硬吃
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务