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;
}
(线段树竟然比暴力还慢…)
方法四(树状数组):艹完暴力之后,用树状数组优化就会感到十分自然了…