[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;
}

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