結果

問題 No.2248 max(C)-min(C)
ユーザー 👑 Kazun
提出日時 2023-03-17 22:15:39
言語 PyPy3
(7.3.15)
結果
AC  
実行時間 2,328 ms / 3,000 ms
コード長 11,218 bytes
コンパイル時間 383 ms
コンパイル使用メモリ 82,688 KB
実行使用メモリ 270,044 KB
最終ジャッジ日時 2024-09-27 04:58:11
合計ジャッジ時間 27,268 ms
ジャッジサーバーID
(参考情報)
judge5 / judge4
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 3
other AC * 51
権限があれば一括ダウンロードができます

ソースコード

diff #
プレゼンテーションモードにする

class Segment_Tree():
def __init__(self, L, calc, unit):
""" calc L Segment Tree
calc: (2, Monoid)
unit: Monoid calc (xe=ex=xe)
"""
self.calc=calc
self.unit=unit
N=len(L); self.n=N
d=max(1,(N-1).bit_length())
k=1<<d
self.data=data=[unit]*k+L+[unit]*(k-len(L))
self.N=k
self.depth=d
for i in range(k-1,0,-1):
data[i]=calc(data[i<<1], data[i<<1|1])
def get(self, k):
""" k
"""
assert 0<=k<self.N,""
return self.data[k+self.N]
def update(self, k, x):
"""kx,.
k:
x:
"""
assert 0<=k<self.N,""
m=k+self.N
data=self.data; calc=self.calc
data[m]=x
while m>1:
m>>=1
data[m]=calc(data[m<<1], data[m<<1|1])
def product(self, l, r, left_closed=True,right_closed=True):
L=l+self.N+(not left_closed)
R=r+self.N+(right_closed)
vL=self.unit
vR=self.unit
data=self.data; calc=self.calc
while L<R:
if L&1:
vL=calc(vL, data[L])
L+=1
if R&1:
R-=1
vR=calc(data[R], vR)
L>>=1
R>>=1
return calc(vL,vR)
def all_product(self):
return self.data[1]
def max_right(self, left, cond):
""" 2 x 1.\n
(1) r=left or cond(data[left]*data[left+1]*...*data[r-1]): True
(2) r=N or cond(data[left]*data[left+1]*...*data[r]): False
※ cond 調, cond(data[left]*...*data[r-1]) r .
cond:()
cond(unit): True
0<=left<=N
"""
assert 0<=left<=self.N,""
assert cond(self.unit),"."
if left==self.N:
return self.N
left+=self.N
sm=self.unit
calc=self.calc; data=self.data
first=True
while first or (left & (-left))!=left:
first=False
while left%2==0:
left>>=1
if not cond(calc(sm, data[left])):
while left<self.N:
left<<=1
if cond(calc(sm, data[left])):
sm=calc(sm, data[left])
left+=1
return left-self.N
sm=calc(sm, data[left])
left+=1
return self.N
def min_left(self, right, cond):
""" 2 y 1.\n
(1) l=right or cond(data[l]*data[l+1]*...*data[right-1]): True
(2) l=0 or cond(data[l-1]*data[l]*...*data[right-1]): False
※ cond 調, cond(data[l]*...*data[right-1]) l .
cond: ()
cond(unit): True
0<=right<=N
"""
assert 0<=right<=self.N,""
assert cond(self.unit),"."
if right==0:
return 0
right+=self.N
sm=self.unit
calc=self.calc; data=self.data
first=1
while first or (right & (-right))!=right:
first=0
right-=1
while right>1 and right&1:
right>>=1
if not cond(calc(data[right], sm)):
while right<self.N:
right=2*right+1
if cond(calc(data[right], sm)):
sm=calc(data[right], sm)
right-=1
return right+1-self.N
sm=calc(data[right], sm)
return 0
def __getitem__(self,k):
return self.get(k)
def __setitem__(self,k,x):
return self.update(k,x)
def __iter__(self):
for i in range(self.n):
yield self.get(i)
#==================================================
" Reference: https://qiita.com/tatyam/items/492c70ac4c955c055602"
# ※ O(sqrt(N)) per query , .
from bisect import bisect_left, bisect_right, insort
class Sorted_Multiset:
BUCKET_RATIO=50
REBUILD_RATIO=170
def __init__(self, A=[]):
A=list(A)
if not all(A[i]<=A[i+1] for i in range(len(A)-1)):
A=sorted(A)
self.__build(A)
return
def __build(self, A=None):
if A is None:
A=list(self)
self.N=N=len(A)
K=1
while self.BUCKET_RATIO*K*K<N:
K+=1
self.list=[A[N*i//K: N*(i+1)//K] for i in range(K)]
def __iter__(self):
for A in self.list:
for a in A:
yield a
def __reversed__(self):
for A in reversed(self.list):
for a in reversed(A):
yield a
def __len__(self):
return self.N
def __bool__(self):
return bool(self.N)
def __str__(self):
string=str(list(self))
return "{"+string[1:-1]+"}"
def __repr__(self):
return "Sorted Multiset: "+str(self)
def __find_bucket(self, x):
for A in self.list:
if x<=A[-1]:
return A
else:
return A
def __contains__(self, x):
if self.N==0:
return False
A=self.__find_bucket(x)
i=bisect_left(A,x)
return i!=len(A) and A[i]==x
def add(self, x):
if self.N==0:
self.list=[[x]]
self.N+=1
return
A=self.__find_bucket(x)
insort(A, x)
self.N+=1
if len(A)>len(self.list)*self.REBUILD_RATIO:
self.__build()
def discard(self, x):
if self.N==0:
return False
A=self.__find_bucket(x)
i=bisect_left(A, x)
if not(i!=len(A) and A[i]==x):
return False # x ...
A.pop(i)
self.N-=1
if len(A)==0:
self.__build()
return True
def remove(self, x):
if not self.discard(x):
raise KeyError(x)
#=== get, pop
def __getitem__(self, index):
if index<0:
index+=self.N
if index<0:
raise IndexError("index out of range")
for A in self.list:
if index<len(A):
return A[index]
index-=len(A)
else:
raise IndexError("index out of range")
def get_min(self):
if self.N==0:
raise ValueError("This is empty set.")
return self.list[0][0]
def pop_min(self):
if self.N==0:
raise ValueError("This is empty set.")
A=self.list[0]
value=A.pop(0)
self.N-=1
if len(A)==0:
self.__build()
return value
def get_max(self):
if self.N==0:
return ValueError("This is empty set.")
return self.list[-1][-1]
def pop_max(self):
if self.N==0:
raise ValueError("This is empty set.")
A=self.list[-1]
value=A.pop(-1)
self.N-=1
if len(A)==0:
self.__build()
return value
#=== previous, next
def previous(self, value, mode=False):
""" S value ( None)
mode: True "" "" .
"""
if self.N==0:
return None
if mode:
for A in reversed(self.list):
if A[0]<=value:
return A[bisect_right(A,value)-1]
else:
for A in reversed(self.list):
if A[0]<value:
return A[bisect_left(A,value)-1]
def next(self, value, mode=False):
""" S value ( None)
mode: True "" "" .
"""
if self.N==0:
return None
if mode:
for A in self.list:
if A[-1]>=value:
return A[bisect_left(A,value)]
else:
for A in self.list:
if A[-1]>value:
return A[bisect_right(A,value)]
#=== count
def less_count(self, value, equal=False):
""" a < value S a .
equal=True , a < value a <= value .
"""
count=0
if equal:
for A in self.list:
if A[-1]>value:
return count+bisect_right(A, value)
count+=len(A)
else:
for A in self.list:
if A[-1]>=value:
return count+bisect_left(A, value)
count+=len(A)
return count
def more_count(self, value, equal=False):
""" a > value S a .
equal=True , a > value a >= value .
"""
return self.N-self.less_count(value, not equal)
#===
def is_upper_bound(self, x, equal=True):
if self.N:
a=self.list[-1][-1]
return (a<x) or (bool(equal) and a==x)
else:
return True
def is_lower_bound(self, x, equal=True):
if self.N:
a=self.list[0][0]
return (x<a) or (bool(equal) and a==x)
else:
return True
#=== index
def index(self, value):
index=0
for A in self.list:
if A[-1]>value:
i=bisect_left(A, value)
if A[i]==value:
return index+i
else:
raise ValueError("{} is not in Multiset".format(value))
index+=len(A)
raise ValueError("{} is not in Multiset".format(value))
#==================================================
def solve():
N=int(input())
A=list(map(int,input().split()))
B=list(map(int,input().split()))
D=[(A[i]+B[i])//2 for i in range(N)]
for i in range(N):
A[i],B[i]=min(A[i],B[i]), max(A[i],B[i])
S=Segment_Tree([(B[i],i) for i in range(N)], max, (-1, 0))
E=Sorted_Multiset()
for i in range(N):
E.add(B[i])
remain=[2]*N
ans=E.get_max()-E.get_min()
while True:
x,i=S.all_product()
if remain[i]==2:
S.update(i,(D[i],i))
E.remove(B[i])
E.add(D[i])
elif remain[i]==1:
S.update(i,(A[i],i))
E.remove(D[i])
E.add(A[i])
else:
break
remain[i]-=1
ans=min(ans, E.get_max()-E.get_min())
return ans
#==================================================
print(solve())
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
0