BZOJ 1012 - 树状数组+维护最大值 / 单调栈+二分 / 暴力(伪单调队列) / 线段树

这道题做法多多… 这道题的出题意图应该是单调栈+二分,即维护一个单调递减的栈,然后二分一下,找到后\(L\)个元素之内最小的即可(注意这个栈里存的是下标,原序列的所有元素都还是要保存的。一开始理解错了,用了pair,然后自己发现了问题之严重…)。

当然还可以大暴力(其实是个伪单调队列?),在黄学长博客上看到的,给吓傻了。

然后本题还可以套数据结构。最暴力的方法是直接上线段树。然后树状数组也可以做,详见iwtwiioi的博客:http://www.cnblogs.com/iwtwiioi/p/3869868.html。

以下把前三种方法的份代码都贴出来,提交记录见下面的网页,我只想说我的内心是崩溃的(忽略最后的两次CE… 黑历史…)
http://www.lydsy.com/JudgeOnline/status.php?problem_id=1012&user_id=yearwhk&language=-1&jresult=-1

代码一(暴力):

// BZOJ 1012_1

#include <cstdio>
#include <cstring>
using namespace std;

 const int N=200000+5;

 #define rep(i,a,b) for (int i=a; i<=b; i++)
 #define dep(i,a,b) for (int i=a; i>=b; i--)
 #define read(x) scanf("%d", &x)
 #define fill(a,x) memset(a, x, sizeof(a))

 int m, mod, x, max[N], num[N];
 char mode;

int main()
{
	read(m); read(mod);
	int pre=0, n=0;
	while (m--) {
		scanf("\n%c%d", &mode, &x);
		if (mode=='A') {
			x=(x+pre)%mod;
			num[++n]=x;
			dep(i,n,1) if (max[i]<x) max[i]=x; else break;
			// max[i]是[i..n]范围内的最大值
		}
		else printf("%d\n", pre=max[n-x+1]);
	}

	return 0;
}

(这份代码很容易被卡掉的啊… 只能说数据太弱…)

代码二(单调栈):

// BZOJ 1012_2

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

 const int N=200000+5;

 #define rep(i,a,b) for (int i=a; i<=b; i++)
 #define dep(i,a,b) for (int i=a; i>=b; i--)
 #define read(x) scanf("%d", &x)
 #define fill(a,x) memset(a, x, sizeof(a))
 #define mp(x,y) make_pair(x,y);

 int m, mod, x, n, s[N], num[N];
 char mode;

int main()
{
	read(m); read(mod);
	int pre=0, n=0, top=0;
	while(m--) {
		scanf("\n%c%d", &mode, &x);
		if (mode=='A') {
			x=(x+pre)%mod;
			num[++n]=x;
			while (top && num[s[top]]<=x) top--;
			s[++top]=n;
		}
		else {
			int y=lower_bound(s+1, s+top+1, n-x+1)-s;
			pre=num[s[y]];
			printf("%d\n", pre);
		}
	}
	return 0;
}

代码三(线段树):

// BZOJ 1012_3

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

 const int N=200000+5, INF=0x3f3f3f3f;
 
 int m, mod;
 char mode;

 struct Node {
 	int l, r, w;
 } maxv[N*4];

 #define read(x) scanf("%d", &x)
 #define rep(i,a,b) for (int i=a; i<=b; i++)

 void build(int o, int L, int R) {
 	maxv[o].l=L, maxv[o].r=R, maxv[o].w=-INF;
 	if (L==R) return;
 	int M=(L+R)>>1;
 	build(o<<1, L, M);
 	build(o<<1|1, M+1, R);
 }

 int query(int o, int x, int y) {
 	int L=maxv[o].l, R=maxv[o].r;
 	if (L==x && R==y) return maxv[o].w;
    int ls=o<<1, rs=o<<1|1, M=(L+R)>>1;
    if (y<=M) return query(ls, x, y);
    else if (x>M) return query(rs, x, y);
    else return max(query(ls, x, M), query(rs, M+1, y));
 }

 void update(int o, int x, int y) {
 	int L=maxv[o].l, R=maxv[o].r;
 	if (L==R) { maxv[o].w=y; return; }
 	int ls=o<<1, rs=o<<1|1, M=(L+R)>>1;
 	if (x<=M) update(ls, x, y); 
 	else update(rs, x, y);
 	maxv[o].w=max(maxv[ls].w, maxv[rs].w);
 }

int main()
{
	read(m); read(mod);
	build(1,1,m);
	int pre=0, n=0, x;
	while (m--) {
		scanf("\n%c%d", &mode, &x);
		if (mode=='A') {
			x=(x+pre)%mod;
			update(1, ++n, x);
		}
		else 
			printf("%d\n", pre=query(1, n-x+1, n));
	}

	return 0;
}

(线段树竟然比暴力还慢…)

方法四(树状数组):艹完暴力之后,用树状数组优化就会感到十分自然了…

posted @ 2016-01-13 21:30  Armeria  阅读(289)  评论(0编辑  收藏  举报