Luogu P1198 BZOJ 1012 最大數 (線段樹)
手動博客搬家: 本文發表於20170821 14:32:05, 原地址https://blog.csdn.net/suncongbo/article/details/77449455
URL: (Luogu) https://www.luogu.org/problem/show?pid=1198, (BZOJ)http://www.lydsy.com/JudgeOnline/problem.php?id=1012
題目大意:
給定一個數列,開始為空。維護兩種操作:
(1) Q L表示查詢當前數列後L個數的最大值。
(2) A N表示在當前數列末尾添加一個新數,這個新數的值等於上一次Q操作的答案加上給定的參數N. 若之前未進行Q操作,則添加的數為N.
思路分析:
此題牽扯到區間最值,我們可以用線段樹進行解決。
但是Q操作由於需要插入元素,所以我們需要將其轉化為能夠利用線段樹解決的問題。
這個序列是動態的,我們不妨將它變成靜態的。
模擬添數的過程,對於每次查詢,存下每次查詢的區間左右端點,對於每次插入,記下插入的數以及它所對應的前一次查詢的編號,便於後面找到上一次查詢的答案。
然後,對記下的插入的數字先建線段樹。
最後,循環枚舉每次詢問,在詢問中繼續枚舉它所對應的插入,更新每次插入的值,以線段樹單點修改的功能來實現。
看似先枚舉詢問,再枚舉插入,是兩重循環,但是由於在此循環中枚舉插入的j只增不減(詳見代碼),因此不會超時。
部分易錯點:
註意第0次詢問(即前面沒有詢問)的情況要單列。
代碼呈現:
(Luogu: Time: 712 MS; Memory: 12.05 MB; Code: 2.04 KB)
(BZOJ: Time: 1088 MS; Memory: 13324 KB; Code: 2333 B)
註: 由於不同OJ評測方式不盡相同,因此時間空間等結果有所差別,屬正常現象
?#include<cstdio> #include<algorithm> using namespace std; const int MAXN = 2e5; int MODN; struct Node { int left,right; int maxi; }; struct SegmentTree { Node nd[MAXN*4+2]; void init() { for(int i=1; i<=MAXN*4; i++) { nd[i].left = nd[i].right = nd[i].maxi = 0; } } void build(int lbound,int rbound,int pos,int a[]) { nd[pos].left = lbound; nd[pos].right = rbound; if(lbound==rbound) { nd[pos].maxi = a[lbound]; return; } int mid = (lbound+rbound)/2; build(lbound,mid,2*pos,a); build(mid+1,rbound,2*pos+1,a); nd[pos].maxi = max(nd[2*pos].maxi,nd[2*pos+1].maxi); } void modify(int bound,int val,int pos) { int mid = (nd[pos].left+nd[pos].right)/2; if(nd[pos].left==nd[pos].right) { nd[pos].maxi = val; return; } if(bound<=mid) modify(bound,val,2*pos); else modify(bound,val,2*pos+1); nd[pos].maxi = max(nd[2*pos].maxi,nd[2*pos+1].maxi); } int query(int lbound,int rbound,int pos) { int mid = (nd[pos].left+nd[pos].right)/2; if(lbound==nd[pos].left && rbound==nd[pos].right) return nd[pos].maxi; int ans; if(rbound<=mid) ans = query(lbound,rbound,2*pos); else if(lbound>mid) ans = query(lbound,rbound,2*pos+1); else ans = max(query(lbound,mid,2*pos),query(mid+1,rbound,2*pos+1)); return ans; } }; SegmentTree st; int a[MAXN+2]; int p[MAXN+2]; int ql[MAXN+2]; int qr[MAXN+2]; int n,m,q; int main() { char ch[5]; int x; n = q = 0; scanf("%d%d",&m,&MODN); for(int i=1; i<=m; i++) { scanf("%s",ch); switch(ch[0]) { case ‘A‘: { scanf("%d",&x); a[++n] = x; p[n] = q; break; } case ‘Q‘: { scanf("%d",&x); ql[++q] = n-x+1; qr[q] = n; break; } } } st.init(); st.build(1,n,1,a); int j = 1; while(j<=n && !p[j]) { j++; } for(int i=1; i<=q; i++) { int ans = st.query(ql[i],qr[i],1); printf("%d\n",ans); while(j<=n && p[j]==i) { st.modify(j,(int)((long long)a[j]+ans)%MODN,1); j++; } } return 0; }?
Luogu P1198 BZOJ 1012 最大數 (線段樹)