题目大意:有N个物品不均匀的放在N个盒子里(有些盒子可能很多,有些盒子可能没有),每个物品和每个盒子都有一个权值,要让每个盒子中只能留下一个物品,第i个盒子多余的物品溢出到第i+1个盒子中(n溢出到1)。求一种方案使得溢出完成后,使满足盒子中物品的权值大于该盒子的权值的盒子尽可能多,输出满足条件的最多盒子数。
数据范围:40%:所有物品开始放在一个盒子里。
100%:N<=5e5
40%:直接田忌赛马即可
100%:平衡树上田忌赛马。首先我们可以证明至少有一个盒子永远不会被其上一个盒子溢出。设Pi为前i个盒子包含的物品数-i (也就是往后溢出的个数),找到最小的Pm,就一定没有物品从m溢出到m+1,假设有一个区间[a,m] (或[a,n]|[1,m])中物品数大于盒子数,那么这个区间溢出的数量即为Pm-Pa<0,得证。所以我们从m+1位置把环展开成数组,维护一个物品集合,对于一个盒子若有比它大的物品就选一个比它大的最小的物品放进去,否则拿一个最小的物品放进去(类似田忌赛马),然后在把下一个盒子中的物品加入进来。这个数据结构要支持加点,求后继,删点,所以用splay。
代码
type
tree=^treenode;
treenode=record
t:longint;
f,l,r:tree;
end;
hash=^hashnode;
hashnode=record
t:longint;
next:hash;
end;
const maxn=500010;
var
n,i,j,min,mini,ans,o:longint;
a,u,v,r:array[0..maxn]of longint;
str:tree;
h:array[0..maxn]of hash;
procedure left(x:tree);
begin
with x^ do
begin
f^.r:=l;
if l<>nil then l^.f:=f;
l:=f;
f:=f^.f;
l^.f:=x;
if f<>nil then
begin
if l=f^.l then f^.l:=x
else f^.r:=x;
end;
end;
end;
procedure right(x:tree);
begin
with x^ do
begin
f^.l:=r;
if r<>nil then r^.f:=f;
r:=f;
f:=f^.f;
r^.f:=x;
if f<>nil then
begin
if r=f^.l then f^.l:=x
else f^.r:=x;
end;
end;
end;
procedure splay(var x,s:tree);
var
p:tree;
begin
if x=nil then exit;
with x^ do
begin
while f<>nil do
begin
if f^.f=nil then
begin
if f^.l=x then right(x)
else left(x);
end
else
begin
if f^.f^.l=f then
begin
if x=f^.l then right(f)
else left(x);
right(x);
end
else
begin
if x=f^.r then left(f)
else right(x);
left(x);
end;
end;
end;
end;
s:=x;
end;
procedure ins(v:longint;var s:tree);
var
p,last:tree;
b:boolean;
begin
if s=nil then
begin
new(s);
with s^ do
begin
t:=v;
l:=nil;
r:=nil;
f:=nil;
end;
exit;
end;
p:=s;
while p<>nil do
begin
last:=p;
if v>p^.t then begin b:=true; p:=p^.r; end
else begin b:=false; p:=p^.l; end;
end;
new(p);
p^.t:=v;
p^.r:=nil;
p^.l:=nil;
p^.f:=last;
if b=true then last^.r:=p
else last^.l:=p;
splay(p,s);
end;
procedure del(var s:tree);
var
p,q:tree;
begin
p:=s^.l;
q:=s^.r;
dispose(s);
if (p=nil)and(q=nil) then begin s:=nil; exit; end;
if p<>nil then
begin
p^.f:=nil;
while p^.r<>nil do p:=p^.r;
splay(p,s);
p^.r:=q;
end;
if q<>nil then
begin
if p=nil then s:=q;
q^.f:=p;
end;
end;
function suc(v:longint;var s:tree):longint;
var
p:tree;
begin
ins(v,s);
p:=s;
p:=p^.r;
if p=nil then begin del(s); exit(-1); end;
while p^.l<>nil do p:=p^.l;
suc:=p^.t;
del(s);
splay(p,str);
end;
procedure addh(x,y:longint);
var
p:hash;
begin
new(p);
p^.t:=y;
p^.next:=h[x];
h[x]:=p;
end;
procedure adds(x:longint);
var
p:hash;
begin
p:=h[x];
while p<>nil do
begin
ins(v[p^.t],str);
p:=p^.next;
end;
end;
begin
readln(n);
for i:=1 to n do
begin
read(a[i]);
inc(r[a[i]]);
addh(a[i],i);
end;
for i:=1 to n do
read(u[i]);
for i:=1 to n do
read(v[i]);
for i:=1 to n do
r[i]:=r[i]+r[i-1];
str:=nil;
min:=maxn;
for i:=1 to n do
if r[i]-i<min then begin min:=r[i]-i; mini:=i; end;
ans:=0;
inc(mini);
for i:=mini to n do
begin
adds(i);
if suc(u[i],str)=-1 then begin o:=suc(0,str); del(str); end
else begin inc(ans); del(str); end;
end;
for i:=1 to mini-1 do
begin
adds(i);
if suc(u[i],str)=-1 then begin o:=suc(0,str); del(str); end
else begin inc(ans); del(str); end;
end;
writeln(ans);
end.