洛谷P1198 [JSOI2008]最大數(線段樹/單調棧)
阿新 • • 發佈:2019-01-09
題目連結:
https://www.luogu.org/problemnew/show/P1198
題目描述
現在請求你維護一個數列,要求提供以下兩種操作:
1、 查詢操作。
語法:Q L
功能:查詢當前數列中末尾L個數中的最大的數,並輸出這個數的值。
限制:LL不超過當前數列的長度。(L > 0)(L>0)
2、 插入操作。
語法:A n
功能:將nn加上tt,其中tt是最近一次查詢操作的答案(如果還未執行過查詢操作,則t=0t=0),並將所得結果對一個固定的常數DD取模,將所得答案插入到數列的末尾。
限制:nn是整數(可能為負數)並且在長整範圍內。
注意:初始時數列是空的,沒有一個數。
輸入輸出格式
輸入格式:
第一行兩個整數,MM和DD,其中MM表示操作的個數(M \le 200,000)(M≤200,000),DD如上文中所述,滿足(0<D<2,000,000,000)(0<D<2,000,000,000)
接下來的MM行,每行一個字串,描述一個具體的操作。語法如上文所述。
輸出格式:
對於每一個查詢操作,你應該按照順序依次輸出結果,每個結果佔一行。
輸入輸出樣例
輸入樣例#1: 複製5 100 A 96 Q 1 A 97 Q 1 Q 2輸出樣例#1: 複製
96 93 96
單調棧解法。因為題目求的是末尾L個數的最大值,利用兩個棧分別儲存最大值和最大值的位置。然後二分查詢。注意二分查詢時上界是總得個數減去區間長度,而不是棧的空間減去區間長度,因為不符合棧的數值已經出棧了。
單調棧解法參考自:https://www.luogu.org/blog/user38348/solution-p1198
#include<iostream> #include<cstdio> #include<cstring> #define ll long long using namespace std; long long Stack[2][200010]; long long cnt=0,top=0; void add(long long val){ cnt++; while(Stack[0][top]<val&&(top>0)) top--; Stack[0][++top]=val; Stack[1][top]=cnt; } long long quiry(long long L){ int l=1,r=top; int ind=cnt-L+1; // int ind=top-L+1; while(l<r){ int mid=(l+r)>>1; if(Stack[1][mid]<ind) l=mid+1; else r=mid; } return Stack[0][l]; } int main(int argc, char** argv) { int M;long long D; scanf("%d %lld",&M,&D); long long t=0; while(M--){ char c; long long d; cin>>c>>d; if(c=='A'){ add((t+d)%D); } else if(c=='Q'){ t=quiry(d); printf("%lld\n",t); } } return 0; }
線段樹解法,維護區間的最大值。
#include <iostream> #include<cstdio> #include<algorithm> #define ll long long using namespace std; const int maxn=200010*4; ll Max[maxn]; void add(int p,int l,int r,int x,ll c){ if(l==r){ Max[p]=c;return; } int mid=(l+r)>>1; if(x<=mid) add(p<<1,l,mid,x,c); else add(p<<1|1,mid+1,r,x,c); Max[p]=max(Max[p<<1],Max[p<<1|1]); } int quiry(int p,int l,int r,int a,int b){ if(a>r||b<l) return -1e8; if(a<=l&&r<=b){ return Max[p]; } int mid=(l+r)>>1; return max(quiry(p<<1,l,mid,a,b),quiry(p<<1|1,mid+1,r,a,b)); } int main(int argc, char** argv) { int M,D; scanf("%d %d",&M,&D); fill(Max,Max+maxn,-1e8); ll t=0; int x=0; while(M--){ char c;int d; cin>>c>>d; if(c=='A'){ x++; ll num=(t+d)%D; add(1,1,200010,x,num); }else if(c=='Q'){ t=quiry(1,1,200010,x-d+1,x); printf("%lld\n",t); } } return 0; }