一种可能可观的处理独立贡献的离线算法
对于一些询问贡献独立且有多次询问的莫队题 , 一般是需要对每一个状态进行数组保存 , 一个一个转移的。
然而前几天听 lxl 说区间逆序对有 \(n^{1.41}\) 的做法。
个人觉得可能是莫队的复杂度被推翻了 , 或者是分块调块的奇技淫巧。
但是后者不太可能 , 确实。块的询问的各个元素和空间是很保持的。
当然也有一定可能。
所以说我又想到了一种可以处理这种询问的一种离线做法。
不过现在这种做法再随机情况下的时间复杂度大概是块为 \(nm^{-\frac 1 2}\) 的两倍。
主要是没打最长不下降子序列来讲复杂度降至最小 , 懒。
不过话说莫队随机不随机都是一样的 , 这种做法也是。
首先考虑一堆询问的区间 , 它们可以用 \(O(n)\) 解决。
它们的共同特征是 : (\(\text{left}_i , \text{right}_i\) 表示第 \(i\) 个询问的左右区间)
\[\text{left}_i \leq \text{left}_{i+1} , \text{right}_i \leq \text{right}_{i+1}
\]
也就是可以有交集并且有前后顺序的序列 , 我们可以用双指针把它直接搞完。
然后我们考虑再一堆询问中求出最大的这种询问 , 也就是传说中按照 \(\text{left}\) 排序后 \(\text{right}\) 的最长不下降子序列。
不过这种东西是 \(O(n \log n)\) 的 , 所以还是比较的慢 , 我对其没有太大的期望。所以我打了一个恶臭贪心。
现在要找一种在 \(O(n)\) 内求出稍有误差的最长不下降子序列。误差就是来去掉 \(\log\) 的。
不过这种东西不一定会有 , 以后慢慢想。
罗列一些效率数据 :
- \(n=5 \times 10^5,m=5 \times 10^4\) , 平均转移 \(468453503\) 次 , \(291\) 层。
- \(n=10^5,m=5 \times 10^5\) , 平均转移 \(375533668\) 次 , \(930\) 层。
- \(n=10^5 , m=10^5\) , 平均转移 \(85613293\) 次 , \(399\) 层。
可能加上优化还是要可观 , 留坑了。
Uses math;
Const
total=100000 << 1;
var
point:array[-1..4,-1..total] of longint;
i,j,n,m,l,r,deep,time,head,last,tail:longint;
procedure Swap(var x,y:longint);var t:longint; begin t:=x; x:=y; y:=t; end;
procedure Sort(l,r,a,b:longint);
var i,j,s1,s2:longint;
begin
i:=l; j:=r; s1:=point[a,(l+r) >> 1]; s2:=point[b,(l+r) >> 1];
repeat
while (point[a,i]<s1)or((point[a,i]=s1)and(point[b,i]<s2)) do inc(i);
while (point[a,j]>s1)or((point[a,j]=s1)and(point[b,j]>s2)) do dec(j);
if i<=j then begin Swap(point[a,i],point[a,j]); Swap(point[b,i],point[b,j]); inc(i); dec(j); end;
until i>=j;
if i<r then Sort(i,r,a,b); if j>l then Sort(l,j,a,b);
end;
begin
read(m); l:=1; r:=1; head:=m;
for i:=1 to m do read(point[1,i],point[2,i]); Sort(1,m,1,2);
repeat
last:=-maxlongint; l:=point[1,1]; r:=point[2,1]; tail:=0; inc(time,r-l+1);
for i:=1 to head do
if (point[2,i]<last) then
begin inc(tail); point[1,tail]:=point[1,i]; point[2,tail]:=point[2,i]; inc(time); end else
begin
for j:=l to point[1,i]-1 do begin inc(time); inc(l); end;
for j:=r to point[2,i]-1 do begin inc(time); inc(r); end; last:=point[2,i];
end;
last:=-maxlongint; l:=point[1,tail]; r:=point[2,tail]; head:=0; inc(time,r-l+1);
for i:=tail downto 1 do
if (point[2,i]<last) then
begin inc(head); point[1,head]:=point[1,i]; point[2,head]:=point[2,i]; inc(time); end else
begin
for j:=l downto point[1,i]+1 do begin inc(time); dec(l); end;
for j:=r to point[2,i]-1 do begin inc(time); inc(r); end; last:=point[2,i];
end;
writeln(head,' ',time); inc(deep);
until head=0;
writeln(time,' ',deep);
end.
完结撒花!✿✿ヽ(゚▽゚)ノ✿

浙公网安备 33010602011771号