BZOJ 1012: [JSOI2008]最大数maxnumber
现在请求你维护一个数列,要求提供以下两种操作: 1、 查询操作。 语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值。 限制:L不超过当前数列的长度。 2、 插入操作。 语法:A n 功能:将n加上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取模,将所得答案插入到数列的末尾。 限制:n是非负整数并且在长整范围内。 注意:初始时数列是空的,没有一个数。
http://www.lydsy.com/JudgeOnline/problem.php?id=1012
/*
* 分析:
* 单调队列加暴力。
* 这个程序优化的地方:可以只存标号,每次Q操作的时候直接二分。
* */
#include <cstdio> #include <cstring> #include <iostream> using namespace std; const int X = 200005; struct node{ int id,val; }q[X]; int main(){ int n,m; while(cin>>n>>m){ int pre = 0; int x; char op[2]; int head = 0,tail = 0; int len = 0; for(int i=1;i<=n;i++){ scanf("%s%d",op,&x); if(op[0]=='A'){ x = (x+pre)%m; while(tail&&q[tail-1].val<=x) tail --; q[tail].val = x; q[tail++].id = ++len; } else{ for(int j=tail-1;j>=0;j--){ if(q[j].id+x<=len) break; else pre = q[j].val; } printf("%d\n",pre); } } } return 0; }
第二种方法:
/*
* 分析:
* 建立线段树
* 对于A操作,只需要update一下
* 对于Q操作,只需要query一下就好了。。
*
* */
#include <cstdio> #include <cstring> #include <iostream> using namespace std; const int X = 200002; #define debug puts("here"); struct seg_tree{ int l,r; int val; int mid(){ return (l+r)>>1; } }tree[X<<2]; void build(int l,int r,int rt){ tree[rt].l = l; tree[rt].r = r; if(l==r) return; int mid = tree[rt].mid(); build(l,mid,rt<<1); build(mid+1,r,rt<<1|1); } void update(int pos,int val,int rt){ if(tree[rt].l==tree[rt].r){ tree[rt].val = val; return; } int mid = tree[rt].mid(); if(mid>=pos) update(pos,val,rt<<1); else update(pos,val,rt<<1|1); tree[rt].val = max(tree[rt<<1].val,tree[rt<<1|1].val); } int query(int l,int r,int rt){ if(l<=tree[rt].l&&r>=tree[rt].r) return tree[rt].val; int mid = tree[rt].mid(); int ans = 0; if(l<=mid) ans = max(ans,query(l,r,rt<<1)); if(r>mid) ans = max(ans,query(l,r,rt<<1|1)); return ans; } int main(){ int n,m; while(cin>>n>>m){ char op[2]; int x; int pre = 0; int len = 0; build(1,n,1); while(n--){ scanf("%s%d",op,&x); if(op[0]=='A') update(++len,(pre+x)%m,1); else{ pre = query(len-x+1,len,1); printf("%d\n",pre); } } } return 0; }