[JSOI2008]最大数
题目描述
现在请求你维护一个数列,要求提供以下两种操作:
1、 查询操作。
语法:Q L
功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值。
限制:L不超过当前数列的长度。
2、 插入操作。
语法:A n
功能:将n加上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取模,将所得答案插入到数列的末尾。
限制:n是整数(可能为负数)并且在长整范围内。
注意:初始时数列是空的,没有一个数。
输入输出格式
输入格式:
第一行两个整数,M和D,其中M表示操作的个数(M <= 200,000),D如上文中所述,满足(0<D<2,000,000,000)
接下来的M行,每行一个字符串,描述一个具体的操作。语法如上文所述。
输出格式:
对于每一个查询操作,你应该按照顺序依次输出结果,每个结果占一行。
输入输出样例
输入样例#1:
5 100 A 96 Q 1 A 97 Q 1 Q 2
输出样例#1:
96 93 96
题解:
运用线段树的算法。
这道题看似长度是变化的,其实可以转化
直接将序列看做1~m的数列,将数一个一个加入,并记录当前位置就行了
首先建树,把所有的节点的值赋成min_int。用[i,j]表示该区间的最大值。
1)读入Q L操作。用len表示区间的大小,在len+1的位置放入(L+T)%D的值。
2)读入A n操作。输出区间[len-n+1,len]这个区间中的最大值,并把t的值进行更新。
此题还可以用二分和单调栈
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 int M,D,t=0; 6 int size; 7 int a[200500]; 8 int num[200500]; 9 int main() 10 { 11 int Ln,len=0; 12 char QA[5]; 13 scanf("%d%d", &M, &D); 14 while(M--) 15 { 16 scanf("%s %d", QA, &Ln); 17 if(QA[0] == 'A')//查询操作 18 { 19 Ln=(Ln+t)%D; 20 num[++len]=Ln;//每次加入一个Ln,num数组长度++ 21 while(size&&num[a[size]]<=Ln) 22 size--;//单调栈操作 23 a[++size]=len; 24 } 25 else //插入操作 26 { 27 int pos=lower_bound(a+1,a+size+1,len-Ln+1)-a; //二分查找 28 t=num[a[pos]]; 29 cout<<t<<endl; 30 } 31 } 32 return 0; 33 }
线段树
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 int c[800001],ans; 6 void add(int rt,int l,int r,int p,int k) 7 { 8 if (l==r) 9 { 10 c[rt]=k; 11 return; 12 } 13 int mid=(l+r)>>1; 14 if (p<=mid) add(rt<<1,l,mid,p,k); 15 else add(rt<<1|1,mid+1,r,p,k); 16 c[rt]=max(c[rt<<1],c[rt<<1|1]); 17 } 18 int query(int rt,int l,int r,int L,int R) 19 { 20 if (l>=L&&r<=R) 21 { 22 return c[rt]; 23 } 24 int mid=(l+r)>>1,s=-2147283647; 25 if (L<=mid) s=max(s,query(rt<<1,l,mid,L,R)); 26 if (R>mid) s=max(s,query(rt<<1|1,mid+1,r,L,R)); 27 return s; 28 } 29 void build(int rt,int l,int r) 30 { 31 c[rt]=-2147283647; 32 if (l==r)return; 33 int mid=(l+r)>>1; 34 build(rt<<1,l,mid);build(rt<<1|1,mid+1,r); 35 } 36 int main() 37 {int n; 38 char ch; 39 int m,d,t,i,l; 40 cin>>m>>d; 41 t=0; 42 int x=0; 43 build(1,1,m); 44 for (i=1;i<=m;i++) 45 { 46 cin>>ch; 47 if (ch=='A') 48 { 49 scanf("%d",&n); 50 n=(n+t)%d; 51 x++; 52 add(1,1,m,x,n); 53 } 54 else 55 { 56 scanf("%d",&l); 57 ans=query(1,1,m,x-l+1,x); 58 t=ans; 59 printf("%d\n",ans); 60 } 61 } 62 }