[BZOJ] 1012 [JSOI2008]最大数maxnumber

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

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

Sample Input
5 100

A 96

Q 1

A 97

Q 1

Q 2
Sample Output
96

93

96

分块大力搞,luogu最后一个点会T。

/**************************************************************
    Problem: 1012
    User: GhostCai
    Language: C++
    Result: Accepted
    Time:908 ms
    Memory:7476 kb
****************************************************************/

#include<iostream>
#include<cstdio>
#include<cmath>
#define R register
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
typedef long long ll;

inline ll rd(){
    ll ret=0,f=1;char c;
    while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
    while(isdigit(c))ret=ret*10+c-'0',c=getchar();
    return ret*f;
}


const int MAXB=1024<<1;
const int MAXN=262144<<1;
int l[MAXB],r[MAXB],belong[MAXN];
ll mx[MAXB];
int block,num;
int mod,n;

inline void build(){
    block=sqrt(n)/2;
    num=n/block;
    if(n%block) num++;
    for(R int i=1;i<=num;i++){
        l[i]=(i-1)*block+1;
        r[i]=i*block;
    }
    for(R int i=1;i<=n;i++) belong[i]=(i-1)/block+1;
}

int cnt;
ll a[MAXN];

inline void updata(ll x){
    a[++cnt]=x;
    mx[belong[cnt]]=max(mx[belong[cnt]],x);
}

inline int query(ll x){
    int p=cnt-x+1;
    ll ret=0;
    if(belong[p]==belong[cnt]){
        for(R int i=p;i<=cnt;i++) ret=max(ret,a[i]);
        return ret;
    }
    for(R int i=p;i<=r[belong[p]];i++) ret=max(ret,a[i]);
    for(R int i=belong[p]+1;i<belong[cnt];i++) ret=max(ret,mx[i]);
    for(R int i=l[belong[cnt]];i<=cnt;i++) ret=max(ret,a[i]);
    return ret;
}

int main(){
    n=rd();mod=rd();
    build();
    char s[5];ll x,t=0;
    for(R int i=1;i<=n;i++){
        scanf("%s",s);
        x=rd();
        if(s[0]=='A'){
            x+=t;
            while(x<0) x+=mod;
//          cout<<"UPDATA:"<<x<<endl;
            updata(x%mod);
        }else{
            t=query(x);
            printf("%lld\n",t);
        }
    }
    return 0;
}

线段树,长时间不写生疏了,感觉不太好

#include<iostream>
#include<cstdio>

using namespace std;

const long long MAXN=4000005;

inline long long rd() {
    long long ret=0,f=1;
    char c;
    while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
    while(isdigit(c))ret=ret*10+c-'0',c=getchar();
    return ret*f;
}


struct Seg{
    #define ls (now<<1)
    #define rs ((now<<1)+1)
    long long mx[MAXN];
    void pushup(long long now){mx[now]=max(mx[ls],mx[rs]);}
    void updata(long long now,long long L,long long R,long long l,long long r,long long w){
        if(L<=l&&r<=R) {mx[now]=w;return;}
        long long mid=(l+r)>>1;
        if(L<=mid) updata(ls,L,R,l,mid,w);
        if(mid <R) updata(rs,L,R,mid+1,r,w);
        pushup(now);
    }
    long long query(long long now,long long L,long long R,long long l,long long r){
        if(L<=l&&r<=R) return mx[now];


        long long mid=(l+r)>>1,ret=0;
        if(L<=mid) ret=max(ret,query(ls,L,R,l,mid));
        if(mid <R) ret=max(ret,query(rs,L,R,mid+1,r));
        return ret;
    }       
}seg;

long long p;
long long m,mod;

signed main(){
    m=rd();mod=rd();
    char s[5];long long x,t=0;
    for(long long i=1;i<=m;i++){
        scanf("%s",s);x=rd();
        if(s[0]=='Q') {
            t=seg.query(1,p-x+1,p,1,200000);
            t%=mod;
            printf("%d\n",t);
        }
        else ++p,seg.updata(1,p,p,1,200000,(x+t)%mod);
    }
    return 0;
}

常数最小的方法,新科技,动态ST表,适用于只往后插入的。
f[i][j]为i往前(1 << j)的最大值,假设已经维护好了前i-1位,那么新加入一位不会对前面造成影响,可以在O(logn)的时间完成更新。

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;

const int MAXN=200005;

typedef long long ll;

inline ll rd(){
    ll ret=0,f=1;char c;
    while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
    while(isdigit(c))ret=ret*10+c-'0',c=getchar();
    return ret*f;
}

ll f[MAXN][32];
ll m,mod;
int p;

int main(){
    m=rd();mod=rd();
    char s[5];ll x,t=0;
    while(m--){
        scanf("%s",s);x=rd();
        if(s[0]=='Q') {
            int len=log2(x);
            printf("%lld\n",t=max(f[p][len],f[p-x+(1<<len)][len])%mod);
        }else{
            f[++p][0]=(x+t)%mod;
            for(int i=1;p-(1<<i)>=0;i++) f[p][i]=max(f[p][i-1],f[p-(1<<(i-1))][i-1]);
        }
    }
    return 0;
}
posted @ 2018-06-12 08:39  GhostCai  阅读(102)  评论(0编辑  收藏  举报