• BZOJ 1012 [JSOI2008]最大数maxnumber


    1012: [JSOI2008]最大数maxnumber

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

    题解:先写个线段树拿分再说。不过我的处理方式很奇怪?不过幸好常数小。。。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cmath>
     4 #include<algorithm>
     5 #include<queue>
     6 #include<cstring>
     7 #define PAU putchar(' ')
     8 #define ENT putchar('
    ')
     9 #define CH for(int d=0;d<2;d++) if(ch[d])
    10 #define lson x->ch[0],L,M
    11 #define rson x->ch[1],M+1,R
    12 using namespace std;
    13 const int maxn=200000+10,maxnode=400000+10,inf=-1u>>1;
    14 int mod,last,ql,qr,pos,cv,_mx,n,len=0;
    15 struct node{
    16     node*ch[2];int mx;node(){mx=-inf;}
    17     void update(){mx=-inf;CH{if(ch[d]->mx>mx)mx=ch[d]->mx;}return;}
    18 }seg[maxnode],*nodecnt=seg,*root;
    19 void build(node*&x=root,int L=1,int R=n){
    20     x=nodecnt++;if(L==R)return;int M=L+R>>1;build(lson);build(rson);return;
    21 }
    22 void update(node*&x,int L,int R){
    23     if(L==R){x->mx=cv;return;}int M=L+R>>1;
    24     if(pos<=M)update(lson);else update(rson);x->update();
    25 }
    26 void query(node*x,int L,int R){
    27     if(ql<=L&&R<=qr){_mx=max(_mx,x->mx);return;}int M=L+R>>1;
    28     if(ql<=M)query(lson);if(qr>M)query(rson);return;
    29 }
    30 inline int read(){
    31     int x=0,sig=1;char ch=getchar();
    32     while(!isdigit(ch)){if(ch=='-') sig=-1;ch=getchar();}
    33     while(isdigit(ch)) x=10*x+ch-'0',ch=getchar();
    34     return x*sig;
    35 }
    36 inline void write(int x){
    37     if(x==0){putchar('0');return;}if(x<0) putchar('-'),x=-x;
    38     int len=0,buf[15];while(x) buf[len++]=x%10,x/=10;
    39     for(int i=len-1;i>=0;i--) putchar(buf[i]+'0');return;
    40 }
    41 inline char readc(){
    42     char ch=getchar();for(;!isalpha(ch);ch=getchar());return ch;
    43 }
    44 void init(){
    45     n=read();mod=read();build();
    46     for(int i=1;i<=n;i++){
    47         if(readc()=='A')cv=(last+read())%mod,len++,pos=len,update(root,1,n);
    48         else{
    49             _mx=-inf;ql=len-read()+1;qr=len;query(root,1,n);write(_mx);ENT;last=_mx;
    50         }
    51     }
    52     return;
    53 }
    54 void work(){
    55     return;
    56 }
    57 void print(){
    58     return;
    59 }
    60 int main(){
    61     init();work();print();return 0;
    62 }

    当然这道题还有一个神奇的做法:观察到如果一个数出现在某个数后边,并且这个数大于之前的数,那么之前的数无论如何也不会成为最大的数的。

    所以我们可以维护一个单调的东西。然后就没有然后了。

    还有,以后别写二分了!!!!!!!

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cmath>
     4 #include<algorithm>
     5 #include<queue>
     6 #include<cstring>
     7 #define PAU putchar(' ')
     8 #define ENT putchar('
    ')
     9 using namespace std;
    10 const int maxn=200000+10,inf=-1u>>1;
    11 int s[maxn],top=0,n,mod,v[maxn],len=0,last;
    12 inline int read(){
    13     int x=0,sig=1;char ch=getchar();
    14     while(!isdigit(ch)){if(ch=='-') sig=-1;ch=getchar();}
    15     while(isdigit(ch)) x=10*x+ch-'0',ch=getchar();
    16     return x*=sig;
    17 }
    18 inline void write(int x){
    19     if(x==0){putchar('0');return;}if(x<0) putchar('-'),x=-x;
    20     int len=0,buf[15];while(x) buf[len++]=x%10,x/=10;
    21     for(int i=len-1;i>=0;i--) putchar(buf[i]+'0');return;
    22 }
    23 inline char readc(){
    24     char ch=getchar();for(;!isalpha(ch);ch=getchar());return ch;
    25 }
    26 void init(){
    27     n=read();mod=read();
    28     for(int i=1;i<=n;i++){
    29         if(readc()=='A'){
    30             int cv=(read()+last)%mod;  
    31             v[++len]=cv;
    32             while(top&&v[s[top]]<=cv)top--;  
    33             s[++top]=len;
    34         } else {
    35             int pos=lower_bound(s+1,s+top+1,len-read()+1)-s;
    36             write(last=v[s[pos]]);ENT;
    37         }
    38     }
    39     return;
    40 }
    41 void work(){
    42     return;
    43 }
    44 void print(){
    45     return;
    46 }
    47 int main(){
    48     init();work();print();return 0;
    49 }

    GYH神犇还提出了离线RMQ的思想。可以发现,每一次插入数即为新建一个集合,而删除一个数即将两集合合并,每次询问则为查询一个数所在的集合的代表元素。这正好是并查集所支持的各种操作。而并查集的每次操作的均摊复杂度接近O(1),所以RMQ的离线问题也可以在O(N+Q)的时间内解决,空间复杂度也是O(N+Q)。

    但是。。。这个跟普通的二分跑得差不多,不过代码复杂度少了很多。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cmath>
     4 #include<algorithm>
     5 #include<queue>
     6 #include<cstring>
     7 #define PAU putchar(' ')
     8 #define ENT putchar('
    ')
     9 using namespace std;
    10 const int maxn=200000+10;
    11 int stack[maxn],top=0,fa[maxn],A[maxn];
    12 int find(int x){if(fa[x]==x)return x;return fa[x]=find(fa[x]);}
    13 inline int read(){
    14     int x=0,sig=1;char ch=getchar();
    15     while(!isdigit(ch)){if(ch=='-') sig=-1;ch=getchar();}
    16     while(isdigit(ch)) x=10*x+ch-'0',ch=getchar();
    17     return x*=sig;
    18 }
    19 inline void write(int x){
    20     if(x==0){putchar('0');return;}if(x<0) putchar('-'),x=-x;
    21     int len=0,buf[15];while(x) buf[len++]=x%10,x/=10;
    22     for(int i=len-1;i>=0;i--) putchar(buf[i]+'0');return;
    23 }
    24 inline char readc(){
    25     char ch=getchar();while(!isalpha(ch))ch=getchar();return ch;
    26 }
    27 void init(){
    28     int last=0,m,mod,x,len=0;
    29     m=read();mod=read();
    30     for(int i=1;i<=m;i++) fa[i]=i;
    31     while(m--){
    32         if(readc()=='Q')x=(len-read()),write(last=A[find(x)]),ENT;
    33         else{
    34             A[len]=(last+read())%mod;
    35             while(top&&A[stack[~-top]]<=A[len])fa[stack[--top]]=len;
    36             stack[top++]=len++;
    37         }
    38     }
    39     return;
    40 }
    41 void work(){
    42     return;
    43 }
    44 void print(){
    45     return;
    46 }
    47 int main(){init();work();print();return 0;}
  • 相关阅读:
    一道C#基础题,看你能多长时间做出来?
    终于能在这里安家了
    你知道返回多少吗?(使用Math类)
    关于implicit和explicit关键词的用法
    关于基类与派生类的学习
    js控制输入框
    Oracle 动态SQL返回单条结果和结果集 转帖
    定时器:.NET Framework类库中的Timer类比较(转帖)
    UVA10020 Minimal coverage
    UVA1388 Graveyard
  • 原文地址:https://www.cnblogs.com/chxer/p/4644654.html
Copyright © 2020-2023  润新知