[JSOI2008]最大数maxnumber

1012: [JSOI2008]最大数maxnumber

Time Limit: 3 Sec  Memory Limit: 162 MB
Submit: 5667  Solved: 2461
[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

 

Source

                           [Submit][Status][Discuss]

 
  1.单调队列,比较好理解,就是如果要新加入的数比前面若干个数大,就把这若干个数覆盖掉,通俗点说,又靠后值又大的数比较diao,因为撑死20w个数,所以开两个20w的数组就够了。
  我们平时写单调队列时,貌似比较多的是用两个指针head,tail来维护队列Q[]数组,但这题貌似行不通,因为每次询问的L不固定,不能舍弃数列的任意一部分,所以用了“覆盖”的方法。

  注意:在输入字符A或Q时,如果像我下面那样定义ch[5],用 cin>>ch 是错的,要用scanf("%s",ch); 否则会RE,我也不知道为啥

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 int Q[200005];
 6 int a[200005];
 7 char ch[5];
 8 int L,N,T,D,M,tot;
 9 inline void workA();
10 inline void workQ();
11 int main(){
12     cin>>M>>D;
13     for(int i=1;i<=M;i++){
14         scanf("%s",ch);
15         //cin>>ch;//RE的 
16         if(ch[0]=='A')
17             workA();
18         else
19             workQ();
20     }
21     return 0;
22 }
23 inline void workA(){
24     scanf("%d",&N);
25     a[++tot]=(T+N)%D;
26     for(int i=tot;i;i--){
27         if(Q[i]<a[tot])
28            Q[i]=a[tot];
29         else break;
30     }
31 }
32 inline void workQ(){
33     scanf("%d",&L);
34     printf("%d\n",T=Q[tot-L+1]);
35 }

  

  2.用线段树,相比之下太长了,还容易错,就不分析了,网上随便整的一个代码

  

 1 #include<iostream>
 2 #include<cstdio>
 3 #define inf 0x7fffffff
 4 using namespace std;
 5 int m,mod,last,cnt;
 6 struct data{int l,r,mx;}t[800005];
 7 void build(int k,int l,int r)
 8 {
 9     t[k].l=l;t[k].r=r;t[k].mx=-inf;
10     if(l==r)return;
11     int mid=(l+r)>>1;
12     build(k<<1,l,mid);
13     build(k<<1|1,mid+1,r);
14 }
15 int ask(int k,int x,int y)
16 {
17     int l=t[k].l,r=t[k].r;
18     if(l==x&&r==y)return t[k].mx;
19     int mid=(l+r)>>1;
20     if(y<=mid)return ask(k<<1,x,y);
21     else if(x>mid)return ask(k<<1|1,x,y);
22     else return max(ask(k<<1,x,mid),ask(k<<1|1,mid+1,y));
23 }
24 void insert(int k,int x,int y)
25 {
26     int l=t[k].l,r=t[k].r;
27     if(l==r){t[k].mx=y;return;}
28     int mid=(l+r)>>1;
29     if(x<=mid)insert(k<<1,x,y);
30     else insert(k<<1|1,x,y);
31     t[k].mx=max(t[k<<1].mx,t[k<<1|1].mx);
32 }
33 int main()
34 {
35     scanf("%d%d",&m,&mod);
36     build(1,1,m);
37     for(int i=1;i<=m;i++)
38     {
39         char ch[5];scanf("%s",ch);
40         int x;
41         if(ch[0]=='A')
42         {
43             cnt++;
44             scanf("%d",&x);x=(x+last)%mod;
45             insert(1,cnt,x);
46         }
47         else 
48         {
49             scanf("%d",&x);
50             last=ask(1,cnt-x+1,cnt);
51             printf("%d\n",last);
52         }
53     }
54     return 0;
55 }

 

 

转载于:https://www.cnblogs.com/CXCXCXC/p/4680756.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值