好不容易一次AC的线段树代码,结果别人的队列快那么多。。
题目戳这里
因为在一本通线段树章节里看到的,所以就很直接的往线段树上想了
(还是不能太单纯)
思路是这样的,因为线段树肯定是要知道叶节点个数才能建树(反正我只会这样建),所以就先全部读入,边统计序列的长度。中间如果读到询问操作就用一个数组记录询问区间在总序列中的位置(包括起点和终点)。
知道序列长度以后先建一个空树(如果一次性全部建好显然是不符合题意的)
全部读好以后开始挨个找答案,如果当前询问的末位置还未加入线段树那就往线段树上加数,否则直接query】
代码不是很长略略
type node=record
l,r,max:longint;
end;
var m,p,x,tot,he,ans,i,j:longint;
c:char;
num:array[1..200000]of longint;
len:array[1..200000,1..2]of longint;
t:array[1..800000]of node;
function mm(e,f:longint):longint;
begin
if e>f then exit(e)
else exit(f);
end;
procedure build(k,l,r:longint);
begin
t[k].l:=l;t[k].r:=r;
if l=r then exit;
build(k*2,l,(l+r) div 2);build(k*2+1,(l+r)div 2+1,r);
end;
procedure insert(k,l,q:longint);
var mid:longint;
begin
if t[k].l=t[k].r then begin t[k].max:=q;exit;end;
if t[k].max<q then t[k].max:=q;
mid:=(t[k].l+t[k].r)div 2;
if l<= mid then insert(k*2,l,q)
else insert(k*2+1,l,q);
end;
function query(k,l,r:longint):longint;
var mid:longint;
begin
if (t[k].l=l) and (t[k].r=r) then
begin
exit(t[k].max);
end;
mid:=(t[k].l+t[k].r) div 2;
if r<=mid then exit(query(k*2,l,r));
if l>mid then exit(query(k*2+1,l,r));
exit(mm(query(k*2,l,mid),query(k*2+1,mid+1,r)));
end;
begin
readln(m,p);
tot:=0;he:=0;
for i:=1 to m do
begin
read(c);
if c='A' then
begin
inc(tot);
readln(num[tot]);
end
else begin
readln(x);
inc(he);
len[he,1]:=tot-x+1;
len[he,2]:=tot;
end;
end;
build(1,1,tot);
ans:=0;
i:=1;
j:=1;
while j<=he do
begin
if i<=len[j,2] then
begin
//write((num[i]+ans) mod p,' ');
insert(1,i,(num[i]+ans)mod p);
inc(i);
end
else
begin
ans:=query(1,len[j,1],len[j,2]);
inc(j);
writeln(ans);
end;
end;
end.
然后就看到了另一种更好的方法
维护一个队列,边读入边做,如果是加数就计算出需要加进的数,然后从队列顶端向下搜直到找到一个比该数大的数,把要加的数放在找到的数上面一个,top也设为这个位置。因为被删去的数是在加入的数之前但又不大于加入的数的数,那么要查询的答案一定不会是它们。
查询时可以从顶端直接往下找,找到第一个到序列末端的长度比查询长度长的,输出其上面一个的答案。
(来自洛谷的一份让本安格尔恍然大悟外加一丝悲伤的大佬代码https://www.luogu.org/record/3129708))
第一篇博文写的好垃圾啊
还有94天要加油加油啊,虽然有点孤单,但千万不要放弃