Luogu P1198 BZOJ 1012 最大數(shù) (線段樹)
手動博客搬家: 本文發(fā)表于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
題目大意:
給定一個數(shù)列,開始為空。維護(hù)兩種操作:
(1) Q L表示查詢當(dāng)前數(shù)列后L個數(shù)的最大值。
(2) A N表示在當(dāng)前數(shù)列末尾添加一個新數(shù),這個新數(shù)的值等于上一次Q操作的答案加上給定的參數(shù)N. 若之前未進(jìn)行Q操作,則添加的數(shù)為N.
思路分析:
此題牽扯到區(qū)間最值,我們可以用線段樹進(jìn)行解決。
但是Q操作由于需要插入元素,所以我們需要將其轉(zhuǎn)化為能夠利用線段樹解決的問題。
這個序列是動態(tài)的,我們不妨將它變成靜態(tài)的。
模擬添數(shù)的過程,對于每次查詢,存下每次查詢的區(qū)間左右端點(diǎn),對于每次插入,記下插入的數(shù)以及它所對應(yīng)的前一次查詢的編號,便于后面找到上一次查詢的答案。
然后,對記下的插入的數(shù)字先建線段樹。
最后,循環(huán)枚舉每次詢問,在詢問中繼續(xù)枚舉它所對應(yīng)的插入,更新每次插入的值,以線段樹單點(diǎn)修改的功能來實(shí)現(xiàn)。
看似先枚舉詢問,再枚舉插入,是兩重循環(huán),但是由于在此循環(huán)中枚舉插入的j只增不減(詳見代碼),因此不會超時。
部分易錯點(diǎn):
注意第0次詢問(即前面沒有詢問)的情況要單列。
代碼呈現(xiàn):
(Luogu: Time: 712 MS; Memory: 12.05 MB; Code: 2.04 KB)
(BZOJ: Time: 1088 MS; Memory: 13324 KB; Code: 2333 B)
注: 由于不同OJ評測方式不盡相同,因此時間空間等結(jié)果有所差別,屬正常現(xiàn)象
?#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;
}? 發(fā)表于
2018-12-26 22:43 suncongbo 閱讀(
...) 評論() 編輯 收藏
刷新評論刷新頁面返回頂部
總結(jié)
以上是生活随笔為你收集整理的Luogu P1198 BZOJ 1012 最大数 (线段树)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。