BZOJ_1012_[JSOI2008]_最大数maxnumber_(线段树/树状数组+RMQ)

描述


http://www.lydsy.com/JudgeOnline/problem.php?id=1012

两种操作:

1.求序列末尾n个数中的最大值.

2.在序列末尾插入一个数.

 

分析


线段树求RMQ裸题,不离线也可以做.

我们来说说怎么用树状数组求RMQ.

求区间和值的树状数组中c[i]表示的是区间(i-lowbit(i)+1,c[i])的和值,我们现在让它表示这个区间的最大值.

1.查询操作get_max(l,r).

如果l<=r-lowbit(r)+1.那么c[r]表示的区间全部在(l,r)内部,于是就ret=max(ret,c[r]),r-=lowbit(r).

否则,ret=max(ret,num[r]),r--.

2.插入操作.update(id,x).

求出区间M=(id-lowbit(id),id)的最大值,c[id]=max(M,num[id]).

这样只会用到查询操作,画图可知,每次查询"上去","下来"最多是2logn,所以复杂度是\(O(logn)\)的.

 

 

线段树:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn=200000+5;
 5 struct node{
 6     int l,r,m;
 7 }a[maxn<<2];
 8 int m,d,t,n,cnt;
 9 char str[3];
10 void build(int l,int r,int k){
11     a[k].l=l; a[k].r=r;
12     if(l==r) return;
13     int mid=l+(r-l)/2;
14     build(l,mid,k<<1); build(mid+1,r,k<<1|1);
15 }
16 void update(int id,int x,int k){
17     if(a[k].l==a[k].r){
18         a[k].m=x;
19         return;
20     }
21     int mid=a[k].l+(a[k].r-a[k].l)/2;
22     if(id<=mid) update(id,x,k<<1);
23     else update(id,x,k<<1|1);
24     a[k].m=max(a[k<<1].m,a[k<<1|1].m);
25 }
26 int get_max(int l,int r,int k){
27     if(a[k].l==l&&a[k].r==r) return a[k].m;
28     int mid=a[k].l+(a[k].r-a[k].l)/2;
29     if(r<=mid) return get_max(l,r,k<<1);
30     else if(l>mid) return get_max(l,r,k<<1|1);
31     else return max(get_max(l,mid,k<<1),get_max(mid+1,r,k<<1|1));
32 }
33 int main(){
34     scanf("%d%d",&m,&d);
35     build(1,m,1);
36     while(m--){
37         scanf("%s%d",str,&n);
38         if(str[0]=='A'){
39             cnt++;
40             update(cnt,(t+n)%d,1);
41         }
42         else printf("%d\n",t=get_max(cnt-n+1,cnt,1));
43     }
44     return 0;
45 }
View Code

 

树状数组:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn=200000+5;
 5 int m,d,n,t,cnt;
 6 int a[maxn],c[maxn];
 7 char str[3];
 8 inline int lowbit(int x){ return x&-x; }
 9 int get_max(int l,int r){
10     if(r<l) return 0;
11     int ret=a[r];
12     while(l<=r){
13         if(r-lowbit(r)+1>=l){
14             ret=max(ret,c[r]);
15             r-=lowbit(r);
16         }
17         else ret=max(ret,a[r]), r--;
18     }
19     return ret;
20 }
21 int main(){
22     scanf("%d%d",&m,&d);
23     while(m--){
24         scanf("%s%d",str,&n);
25         if(str[0]=='A'){
26             a[++cnt]=(n+t)%d;
27             c[cnt]=max(get_max(cnt-lowbit(cnt)+1,cnt-1),a[cnt]);
28         }
29         else{
30             printf("%d\n",t=get_max(cnt-n+1,cnt));
31         }
32     }
33     return 0;
34 }
View Code

 

1012: [JSOI2008]最大数maxnumber

Time Limit: 3 Sec  Memory Limit: 162 MB
Submit: 7678  Solved: 3313
[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如上文中所述,满足D在longint内。接下来
M行,查询操作或者插入操作。

Output

  对于每一个询问操作,输出一行。该行只有一个数,即序列中最后L个数的最大数。

Sample Input

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

Sample Output

96
93
96

HINT

  数据如下http://pan.baidu.com/s/1i4JxCH3

Source

posted @ 2016-06-13 10:10  晴歌。  阅读(139)  评论(0编辑  收藏  举报