BZOJ 1012 最大数

    很明显,这是道水题。尽管一开始我还不大相信,在想用什么数据结构才比较好,想过队列,当然线段树肯定也想过了。不过一直在怀疑这题有那么简单吗?不会有坑吧!事实证明没什么坑,可以跳了。最不爽的要数我在网上看到的一个题解,用单调队列写的,就开了两个数组,20行代码搞定了(只跑了400多毫秒)。我一开始写的线段树跑了900多毫秒。无意间,在看别人的博客时,看到了zkw线段树,这一神奇的东西,便学了一下。今晚zkw线段树写完了,才开始写这一博客。其实lrj在白书线段树那一块曾说过线段树有一种自底向上的写法,速度比递归的写法快,大概就是指zkw线段树了。加油。

 

接下来,是最令我感慨的单调队列的代码。

 1 #include<cstdio>
 2 int m,d,a[200001] = {0},t,max[200001] = {0},l=0,p;
 3 char q[1];
 4 int main()
 5 {
 6     scanf("%d%d", &m, &d);
 7     while (m--)
 8     {
 9         scanf("%s%d",q,&p);
10         if(q[0]=='A')
11         {
12             a[++t]=(l+p)%d;
13             for(int i=t;i;i--)
14                 if(max[i]<a[t])max[i]=a[t];
15                 else break;
16         }
17         else printf("%d\n",l=max[t-p+1]);
18     }
19     return 0;
20 }

 

接下来,还有我在网上看到的一个单调栈

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstdio>
 5 using namespace std;
 6 int n,d,t;
 7 int top,len,a[200001],num[200001];
 8 int main()
 9 {
10     int x;char ch[1];
11     scanf("%d%d",&n,&d);
12     while(n--)
13     {
14               scanf("%s%d",ch,&x);
15               if(ch[0]=='A')
16               {
17                       x=(x+t)%d;
18                       num[++len]=x;
19                       while(top&&num[a[top]]<=x)top--;
20                       a[++top]=len;      
21                       }
22               else{
23                   int y=lower_bound(a+1,a+top+1,len-x+1)-a;
24                   t=num[a[y]];
25                   printf("%d\n",t=num[a[y]]);
26               }
27           }
28     return 0;
29 }

 

最后就是zkw线段树了。(重点)(其实这种写法也要比自上而下的容易写)。

 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 int num[1<<19|1] = {0};
 5 int po = (1<<18)-1;
 6  
 7 void update(int pos,int key)
 8 {
 9     pos += po;
10     for(num[pos] = key, pos>>=1; pos; pos>>=1){
11         num[pos] = max(num[pos<<1],num[pos<<1|1]);
12     }
13 }
14  
15 int query(int l,int r)
16 {
17     int ans = 0;
18     for(l = po+l-1, r = po+r+1; l^r^1; l >>= 1, r >>= 1){
19         if( !(l&1) ) ans = max(ans,num[l^1]);
20         if( r & 1 ) ans = max(ans,num[r^1]);
21     }
22     return ans;
23 }
24  
25 int main()
26 {
27     int m, d, x, ans = 0, cnt = 0; char c[5];
28     scanf("%d %d", &m,&d); 
29     while( m-- ){
30         scanf("%s %d", c,&x);
31         if( c[0] == 'A' ){
32             update(++cnt,(x+ans)%d);
33         }
34         else {
35             printf("%d\n",ans=query(cnt-x+1,cnt));
36         }
37     }
38     return 0;
39 }

 

1012: [JSOI2008]最大数maxnumber

Time Limit: 3 Sec  Memory Limit: 162 MB
Submit: 6668  Solved: 2865
[Submit][Status][Discuss]

Description

现在请求你维护一个数列,要求提供以下两种操作: 1、 查询操作。语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值。限制:L不超过当前数列的长度。 2、 插入操作。语法:A n 功能:将n加上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取模,将所得答案插入到数列的末尾。限制:n是非负整数并且在长整范围内。注意:初始时数列是空的,没有一个数。

Input

第一行两个整数,M和D,其中M表示操作的个数(M <= 200,000),D如上文中所述,满足(0

Output

对于每一个查询操作,你应该按照顺序依次输出结果,每个结果占一行。

Sample Input

5 100
A 96
Q 1
A 97
Q 1
Q 2

Sample Output

96
93
96

HINT

posted on 2015-12-24 20:04  83131  阅读(192)  评论(0编辑  收藏  举报

导航