\[Description\]
Hack 国的居民人人都是 OI 大师,Hometown 得知便赶紧来到 Hack 国学习。可想要进入 Hack 国并不是件容易的事情,首先就必须通过 Hack 国海关小 B 的考验。小 B 觉得 Hometown 比较菜,于是就扔了一道小水题给 Hometown。
给定一个长度为 n 的数列 a i ,接下来会对这个序列进行 m 次操作。操作类型分为以下两种:
• \(\texttt{1 l r}\),表示将区间 \(l,r\) 轮转一次。具体来说, \(a_l,a_{l+1}..a_r\) 经过一次轮转之后,会变为 \(a_r,a_l,a_{l+1}..a_{r-1}\)。
• \(\texttt{1 l r k}\),询问区间 \(l,r\) 内 \(a_i = k\) 的个数。
可惜 Hometown 还是不会做,他只能期待你能解决这个问题了。
\[Input/Output\]
从文件queue.in中读入数据。
第一行两个整数 n,m,表示序列的长度与操作的次数。
第二行 n 个整数 a i ,表示这个序列。
接下来的 m 行,每行先是一个整数 opt 表示操作的类型。对于 opt = 1 的操作,接下来两个整数 l,r 表示将区间 [l,r] 轮转;对于 opt = 2 的操作,接下来三个整数 l,r,k 表示求区间 [l,r] 内等于 k 的值的个数。
输出到文件queue.out中。
对于每个 2 操作,一行一个整数,表示这次询问的答案。
\[Sample\]
7 6
1 2 2 3 2 1 3
2 3 6 2
1 1 6
2 2 4 1
1 3 6
2 6 7 3
2 3 5 2
2
1
2
3
对于第一次询问,区间 [3,6] 中一共出现了 2 次 2。
随后进行修改,修改之后序列变为 1,1,2,2,3,2,3。
对于第二次询问,区间 [2,4] 中一共出现了 1 次 1。
随后再次修改,修改之后序列变为 1,1,2,2,2,3,3。
对于第三次询问,区间 [6,7] 中一共出现了 2 次 3。
对于第四次询问,区间 [3,5] 中一共出现了 3 次 2。
\[Data\ Constraint\]
\(N,M,a_i \leq 10^5\)
这道题异常简单。
考虑异常的修改和普通的查询,我们可以想到分块。但是如何分块可以试一次修改达到 \(\sqrt{N}\) ? 我们要把每一个块的“轮转”变为 \(O(1)\) 的。总的来说,我们的每一次“轮转”都是将块尾给下一个块的块首,然后再将 \(r\) 放到 \(l\) 的位置。这样子的话我们可以开一个队列,然后进行操作。每一个队列试双端队列,数组开 \(-x \times 10^4~y \times 10^4\)。其中看你往正数还是负数倾斜的大,然后确定 \(x\) 和 \(y\) 的大小。空间复杂度可以做到 \(N \sqrt{N}\)。
我们轮转的操作包括什么呢?
再一个块中暴力不说。
我们用 \(real_1\) 和 \(real_2\) 分别记录 \(l,r\) 所在的块的编号。
然后我们用 \(goal_1\) 和 \(goal_2\) 分别表示 \(l,r\) 所在的块中的位置。这个位置不是第几个,而是它的下标所在。比如我们用 \(queue_{block,node}\) 代表第 \(block\) 块的 \(node\) 的位置 (并不是第 \(node\) 个因为 \(head_{block}\) 可能是负数),我们 \(goal\) 要求的就是这个 \(node\)。那么很显然:
- \(goal[1]:=head_{real_1}+l-(real_1-1) \times node_{num}-1\)
- \(goal[2]:=head_{real_2}+r-(real_2-1) \times node_{num}-1\)
后面是这样子的:
1 3 4 5 6 7
将 2,6 翻转
它的队列是这样的:
1 3
4 5
6 7
那么接下来先把 6 这个位置的数搞进去:
1 6 3
4 5
7
然后把每一个触及到的块都把队尾给(下一个)队头:
1 6
3 4
5 7
搞定
细节很多,要慢慢琢磨。注意我们要定义 \(times_{block,k}\) 代表 \(k\) 在 \(block\) 块的出现次数。查询怎么搞? 同理。
Const
tot=100100;
totalmemory=80000000;
memory=(totalmemory div trunc(sqrt(tot))) div 7;
var
times,queue:array[-1..trunc(sqrt(tot)*1.3),trunc(-memory*2.5)..trunc(memory/2.5)] of longint;
head,tail:array[-1..trunc(sqrt(tot)*1.3)] of longint;
real,goal:array[1..3] of longint;
i,j,n,m,l,r,l1,r1,k,ans,num,mode,node_num,block_num:longint;
function Locate(node:longint):longint;
begin
if node mod node_num=0 then exit(node div node_num);
exit(node div node_num+1);
end;
begin
assign(input,'queue.in');reset(input);
assign(output,'queue.out');rewrite(output);
read(n,m); if (n=0)or(m=0) then halt; node_num:=trunc(sqrt(n)); block_num:=Locate(n);
for i:=1 to block_num do head[i]:=1;
for i:=1 to n do begin read(num); inc(tail[Locate(i)]); queue[Locate(i),tail[Locate(i)]]:=num; inc(times[Locate(i),num]); end;
for i:=1 to m do
begin
read(mode);
if mode=1 then
begin
read(l,r); real[1]:=Locate(l); real[2]:=Locate(r);
goal[1]:=head[real[1]]+l-(real[1]-1)*node_num-1; goal[2]:=head[real[2]]+r-(real[2]-1)*node_num-1;
if real[1]=real[2] then
begin
r:=queue[real[1],goal[2]];
for j:=goal[2] downto goal[1]+1 do queue[real[1],j]:=queue[real[1],j-1];
queue[real[1],goal[1]]:=r;
end else
begin
dec(head[real[1]]); for j:=head[real[1]] to goal[1]-2 do queue[real[1],j]:=queue[real[1],j+1];
dec(tail[real[2]]); goal[3]:=queue[real[2],goal[2]]; dec(times[real[2],goal[3]]);
queue[real[1],goal[1]-1]:=goal[3]; inc(times[real[1],goal[3]]);
for j:=goal[2] to tail[real[2]] do queue[real[2],j]:=queue[real[2],j+1]; queue[real[2],tail[real[2]]+1]:=0;
for j:=real[1] to real[2]-1 do
begin
dec(head[j+1]); queue[j+1,head[j+1]]:=queue[j,tail[j]];
dec(times[j,queue[j,tail[j]]]); inc(times[j+1,queue[j,tail[j]]]);
queue[j,tail[j]]:=0; dec(tail[j]);
end;
end;
end else
begin
read(l,r,k); real[1]:=Locate(l); real[2]:=Locate(r); ans:=0;
l1:=l-(real[1]-1)*node_num-1+head[real[1]]; r1:=r-(real[2]-1)*node_num-1+head[real[2]];
if real[1]=real[2] then
begin
for j:=l1 to r1 do if queue[real[1],j]=k then inc(ans);
end else
begin
for j:=l1 to tail[real[1]] do if queue[real[1],j]=k then inc(ans);
for j:=real[1]+1 to real[2]-1 do inc(ans,times[j,k]);
for j:=head[real[2]] to r1 do if queue[real[2],j]=k then inc(ans);
end;
writeln(ans);
end;
end;
close(input); close(output);
end.