[bzoj1012] [JSOI2008]最大数maxnumber 线段树 动态区间最值

Description

  现在请求你维护一个数列,要求提供以下两种操作:1、 查询操作。语法:Q L 功能:查询当前数列中末尾L
个数中的最大的数,并输出这个数的值。限制:L不超过当前数列的长度。2、 插入操作。语法:A n 功能:将n加
上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取
模,将所得答案插入到数列的末尾。限制:n是非负整数并且在长整范围内。注意:初始时数列是空的,没有一个
数。

Input

  第一行两个整数,M和D,其中M表示操作的个数(M <= 200,000),D如上文中所述,满足D在longint内。接下来
M行,查询操作或者插入操作。

Output

  对于每一个询问操作,输出一行。该行只有一个数,即序列中最后L个数的最大数。

Sample Input

5 100
A 96
Q 1
A 97
Q 1
Q 2

Sample Output

96
93
96


题解:

这题算是比较经典的一道线段树题了。看到各路神犇拿各种niubi算法在代码量和常数上随便吊打线段树,我还是顶住压力写了这一篇线段树题解。

首先我们把线段树建出来,建一棵m大小的线段树。

然后每次'A'操作就是把空白的末尾部位填充要填充的数。

每次'Q'操作就是求末尾长度为l的区间最小值。

这两个操作都可以直接由最基本的线段树完成。

AC代码:

#include<cstdio>
#include<iostream>
#define ll long long
using namespace std;
const int Maxn=200005;
int m,p;
struct node{
	ll x,c;
	int l,r;
}t[Maxn*4];
inline int lson(int rt){
	return rt*2;
}
inline int rson(int rt){
	return rt*2+1;
}
inline ll mx(ll x,ll y){
	return x>y?x:y;
}
inline void pushup(int rt){
	t[rt].x=mx(t[lson(rt)].x,t[rson(rt)].x);
}
inline void build(int l,int r,int rt){
	t[rt].l=l;t[rt].r=r;
	if(l==r)return;
	int mid=l+r>>1;
	build(l,mid,lson(rt));
	build(mid+1,r,rson(rt));
}
inline void update(int l,ll x,int rt){
	if(t[rt].l==l&&t[rt].r==l){
		t[rt].x=x;
		return;
	}
	int mid=t[rt].l+t[rt].r>>1;
	if(l<=mid)update(l,x,lson(rt));
	else update(l,x,rson(rt));
	pushup(rt);
}
inline ll query(int l,int r,int rt){
	if(t[rt].l>=l&&t[rt].r<=r)return t[rt].x;
	int mid=t[rt].l+t[rt].r>>1;ll ans=-1000000000;
	if(l<=mid)ans=mx(ans,query(l,r,lson(rt)));
	if(r>mid)ans=mx(ans,query(l,r,rson(rt)));
	return ans;
}
int main(){
	char inc;ll u,t=0;int cnt=0;
	scanf("%d%d\n",&m,&p);
	build(1,m,1);
	while(m--){
		scanf("%c %lld\n",&inc,&u);
		if(inc=='A'){
			cnt++;
			update(cnt,(u+t)%p,1);
		}
		else{
			t=query(cnt-u+1,cnt,1);
			printf("%lld\n",t);
		}
	}
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章