【BZOJ】1012 最大数

来源:互联网 发布:模拟城市未来之城 mac 编辑:程序博客网 时间:2024/05/18 03:37
【解析1】线段树

[分析]
这道题数据M<=200000,最直观的就是开棵线段树 O(M log M) 就过了。
没想到随手写的居然一次AC了,以后要杜绝这种坏习惯。

[代码]
#include <cstdio>#include <cstring>#include <cstdlib>#include <climits>using namespace std;const int M=200001;const int L=INT_MAX;const int P=INT_MIN;int m,d,q[M][2],qa;struct SegmentTree{int l,r,mx;}tr[M<<2];int lst;inline int read(void){int s=0,f=1; char c=getchar();for (;c<'0'||c>'9';c=getchar()) if (c=='-') f=-1;for (;'0'<=c&&c<='9';c=getchar()) s=(s<<1)+(s<<3)+c-'0';return s*f;}void build(int now,int l,int r){tr[now].l=l;tr[now].r=r;tr[now].mx=L;if (l^r){int mid=l+r>>1;build(now<<1,l,mid);build(now<<1|1,mid+1,r);}}inline int max(int i,int j){return i>j?i:j;}void ins(int now,int loc,int w){if (tr[now].l==tr[now].r) {tr[now].mx=w;return;}int mid=tr[now].l+tr[now].r>>1;ins(now<<1|(loc<=mid?0:1),loc,w);tr[now].mx=max(tr[now<<1].mx,tr[now<<1|1].mx);}int query(int now,int l,int r){if (l<=tr[now].l&&tr[now].r<=r) return tr[now].mx;int mx=P,mid=tr[now].l+tr[now].r>>1;if (l<=mid) mx=max(mx,query(now<<1,l,r));if (mid<r) mx=max(mx,query(now<<1|1,l,r));return mx;}int main(void){char c;m=read(),d=read();for (int i=1;i<=m;i++){scanf("\n%c",&c);if (c=='A') qa++; else q[i][0]=1;q[i][1]=read();}build(1,1,qa),qa=0;for (int i=1;i<=m;i++)if (!q[i][0])ins(1,++qa,(lst+q[i][1])%d);else printf("%d\n",lst=query(1,qa-q[i][1]+1,qa));return 0;}


【解析2】单调队列+二分搜索

[分析]
建一个单调队列,在队列中存储:
loc:表示它是第loc个插入的,也就是原数列的第loc项;
w:表示这个位置的值。

插入操作:
由于对于后面读进来的元素x,如果满足x大于前面的元素y,则y一定不可能是答案。
所以先从队尾把不符合的给删掉,最后再把x插进去。
这样,就能保证单调队列的双重单调性:loc,w。

查询操作:
查找后x位的最大值,那么也就是查找队列从头起第1个在后x位的loc的w。
由于w的单调性,所以要尽可能在前面。
由于loc的单调性,所以可以使用二分查找。

[代码]
#include <cstdio>#include <cstring>#include <cstdlib>using namespace std;const int M=200010;int m,d,lst;struct Q{int w,loc;}q[M];int h,t,ca;inline int read(void){int s=0,f=1; char c=getchar();for (;c<'0'||c>'9';c=getchar()) if (c=='-') f=-1;for (;'0'<=c&&c<='9';c=getchar()) s=(s<<1)+(s<<3)+c-'0';return s*f;}int main(void){char c; int x;m=read(),d=read(),h=1;for (int i=1;i<=m;i++){scanf("\n%c",&c),x=read();if (c=='A'){x=(x+lst)%d,ca++;for (;h<=t&&x>=q[t].w;t--);q[++t].w=x,q[t].loc=ca;}else{int l=h,r=t,mid;for (;l<=r;){mid=l+r>>1;ca-q[mid].loc+1<=x?r=mid-1:l=mid+1;}printf("%d\n",lst=q[l].w);}}return 0;}


【解析3】单调栈:和单调队列差不多.../(ㄒoㄒ)/~~

【小结】对于定向扫过去求最值的问题,可以考虑使用单调栈 or 单调队列。
0 0
原创粉丝点击