[BZOJ 1012] [JSOI2008] 最大数maxnumber

[JSOI2008]最大数maxnumber

Time Limit: 3 Sec Memory Limit: 162 MB

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

题解

树状数组(终于不水题了)(其实还是水~黑)
首先是添加进数组

  • 添加进树状数组y[tail],然后需要比较的是y[tail- 20 ],y[tail- 21 ],y[tail- 22 ]……y[tail-lowbit(tail)+1]

然后是区间查询

  • 我们认为区间左端点为l右端点为r,右端点的范围为[r-lowbit(r)+1,r],如果r-lowbit(r)+1在左端点l内或l上,则比较y[r],然后r变为r-lowbit,否则r变为r-1
var
 x,y:array[0..200000]of longint;
 i,j,k:longint;
 m,d,a,t,l,r:longint;
 v:char;
function max(a,b:longint):longint;
begin
 if a>b
 then exit(a)
 else exit(b);
end;

function lowbit(a:longint):longint;
begin
 exit(a and(-a));
end;

begin
 readln(m,d); t:=0; x[0]:=0;
 for i:=1 to m do
  begin
   readln(v,a);
   if v='A'
   then
    begin
     inc(x[0]);
     x[x[0]]:=(a+t) mod d;
     y[x[0]]:=x[x[0]];
     j:=1;
     while j<lowbit(x[0]) do
      begin
       y[x[0]]:=max(y[x[0]],y[x[0]-j]);
       j:=j*2;
      end;
    end
   else
    begin
     l:=x[0]-a+1; r:=x[0]; t:=0;
     while l<=r do
      if r-lowbit(r)+1>=l
      then begin t:=max(t,y[r]); dec(r,lowbit(r)); end
      else begin t:=max(t,x[r]); dec(r); end;
     writeln(t);
    end;
  end;
end.


你可能感兴趣的:([BZOJ 1012] [JSOI2008] 最大数maxnumber)