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如上文中所述,满足D在longint内。接下来
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
",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
",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
",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;
}