[JSOI2008]最大数

洛咕

题意:现在请求你维护一个数列,要求提供以下两种操作:

1、查询操作.

语法:Q L

功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值。

限制:(L)不超过当前数列的长度。((L > 0))

2、 插入操作。

语法:A n

功能:将(n)加上(t),其中(t)是最近一次查询操作的答案(如果还未执行过查询操作,则(t=0)),并将所得结果对一个固定的常数(D)取模,将所得答案插入到数列的末尾。

限制:(n)是整数(可能为负数)并且在长整范围内。

注意:初始时数列是空的,没有一个数.

分析:本题好像还有什么树状数组,单调栈,ST表等多种做法,当做线段树模板题来写吧.对于查询操作就是区间([n-L+1,n])最大值,线段树维护这个东西.对于一个插入操作,不妨把初始序列看做长度为200000的空线段树(每个值都是零),则插入操作就是单点修改操作了.

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
    int x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;
}
const int N=200005;
int n,m,mod,last,a[N],maxn[N<<2];
inline void change(int p,int l,int r,int pos,int val){
	if(r<pos||l>pos)return;
	if(l==r&&l==pos){maxn[p]=val;return;}
	int mid=(l+r)>>1;
	change(p<<1,l,mid,pos,val);
	change(p<<1|1,mid+1,r,pos,val);
	maxn[p]=max(maxn[p<<1],maxn[p<<1|1]);
}
inline int ask(int p,int l,int r,int ql,int qr){
	if(r<ql||l>qr)return -2e9;
	if(ql<=l&&qr>=r)return maxn[p];
	int mid=(l+r)>>1;
	return max(ask(p<<1,l,mid,ql,qr),ask(p<<1|1,mid+1,r,ql,qr)); 
}
int main(){
	m=read();mod=read();
	while(m--){
		char ch;cin>>ch;int x=read();
		if(ch=='A'){
			x=(x+last)%mod;a[++n]=x;
			change(1,1,N-5,n,x);
		}
		else{
			if(x==1){
				last=a[n];
				printf("%d
",a[n]);
				continue;
			}
			int l=n-x+1,r=n,ans=ask(1,1,N-5,l,r);
			last=ans;printf("%d
",ans);
		}
	}
    return 0;
}

原文地址:https://www.cnblogs.com/PPXppx/p/11649224.html