题解 P4168 【[Violet]蒲公英】
好久以前就要写的博客拖到运动会来写....(当时思路好像还是原创的,现在不是了)
先说明并没有
本篇适合于刚刚入手分块的蒟蒻(超详细)。
首先我们先把区间分块(废话)。考虑到一个区间的众数是要不是这个区间的最大块的答案,就是旁边多出来的边角的数字。因为任何数在最大块中出现的次数 肯定小于 最大块的众数的出现次数,而边角却可以让自己的出现次数增加来达到超越最大块的众数的效果。
(如图,黄色部分的数字的出现次数可能超过最大块众数
所以我们就可以预处理出第
首先要预处理每个块中数的出现次数。如果我们定义数组
j:=1;
for i:=1 to n do
begin
inc(times[j,num[i]]);
if i mod (block_num-1)=0 then // block_num 代表块的个数
begin
for k:=1 to tail do times[j+1,k]:=times[j,k]; // 全部数字都要继承
inc(j); // 又过了一块
end;
end;
接下来我们要快速构造数组
for i:=1 to block_num do
for j:=i to block_num do
begin
now:=ans[i,j-1]; // 上一次的答案
for k:=(j-1)*node_num+1 to min(n,j*node_num) do // 这个块
begin
tmp1:=times[j,num[k]]-times[i-1,num[k]]; // 现有答案的出现次数
tmp2:=times[j,now]-times[i-1,now]; // 可能的数的出现次数
if (tmp1>tmp2)or((tmp1=tmp2)and(num[k]<now)) then now:=num[k]; // 更好就更新
end;
ans[i,j]:=now;
end;
查询的思路讲得很清楚了,大家主要看注释。
讲一下定义:
begin
Ready; now:=0; recf[0]:=0; // 一开始 now=0
for i:=1 to m do
begin
read(l,r);
real[1]:=Locate(l); real[2]:=Locate(r); bucket[0]:=0;
if real[2]-real[1]<=1 then // 可以暴力就暴力 复杂度是两个 sqrt(n)
begin
now:=0;
for k:=l to r do
begin
inc(bucket[num[k]]);
if (bucket[num[k]]>bucket[now])or((bucket[num[k]]=bucket[now])and(now>num[k])) then now:=num[k];
end;
for k:=l to r do bucket[num[k]]:=0;
writeln(recf[now]);
end
else
begin // 只有左右需要暴力,还要清空,所以是四个 sqrt(n)
now:=ans[real[1]+1,real[2]-1]; // 最大块的出现次数
for k:=l to min(n,real[1]*node_num) do // 左边角暴力
begin
inc(bucket[num[k]]);
tmp1:=bucket[num[k]]+times[real[2]-1,num[k]]-times[real[1],num[k]];
tmp2:=bucket[now]+times[real[2]-1,now]-times[real[1],now];
if (tmp1>tmp2)or((tmp1=tmp2)and(now>num[k])) then now:=num[k];
end;
for k:=(real[2]-1)*node_num+1 to r do // 右边角暴力
begin
inc(bucket[num[k]]);
tmp1:=bucket[num[k]]+times[real[2]-1,num[k]]-times[real[1],num[k]];
tmp2:=bucket[now]+times[real[2]-1,now]-times[real[1],now];
if (tmp1>tmp2)or((tmp1=tmp2)and(now>num[k])) then now:=num[k];
end;
// 清空
for k:=l to min(n,real[1]*node_num) do bucket[num[k]]:=0;
for k:=(real[2]-1)*node_num+1 to r do bucket[num[k]]:=0;
writeln(recf[now]);
end;
end;
end.
写了好久,希望给个赞再走