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
A 96
Q 1
A 97
Q 1
Q 2
Sample Output
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;
}