BZOJ1012 [JSOI2008]最大数maxnumber
题目描述:
现在请求你维护一个数列,要求提供以下两种操作:
1、 查询操作。语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值。限制:L不超过当前数列的长度。
2、 插入操作。语法:A n 功能:将n加上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),
并将所得结果对一个固定的常数D取模,将所得答案插入到数列的末尾。限制:n是非负整数并且在长整范围内。
注意:初始时数列是空的,没有一个数。
题解:
我们考虑序列最多会有m个数,并且看到区间查询,想到线段树。
对于操作2,我们直接在线段树上区间求和即可。
对于操作1,我们转换一下,即每次在线段树末尾单点修改即可。
附上代码:
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; int m,d,idx; long long maxx[1000100],t; void pushup(int k) { maxx[k]=max(maxx[k<<1],maxx[k<<1|1]); } void update(int l,int r,int p,long long v,int k) { if(l==r) { maxx[k]=v; return; } int mid=(l+r)>>1; if(mid>=p) update(l,mid,p,v,k<<1); else update(mid+1,r,p,v,k<<1|1); pushup(k); } long long query(int l,int r,int x,int y,int k) { if(x<=l&&r<=y) return maxx[k]; int mid=(l+r)>>1; long long ans=0; if(x<=mid) ans=max(ans,query(l,mid,x,y,k<<1)); if(y>mid) ans=max(ans,query(mid+1,r,x,y,k<<1|1)); return ans; } int main() { scanf("%d%d",&m,&d); for(int i=1;i<=m;i++) { char s[2]; scanf("%s",s); if(s[0]=='A') { ++idx; long long x; scanf("%lld",&x); update(1,m,idx,(x+t)%d,1); } else { int x; scanf("%d",&x); t=query(1,m,idx-x+1,idx,1); printf("%lld\n",t); } } }