class Segment_Tree(): def __init__(self, L, calc, unit): """ calc を演算とするリスト L の Segment Tree を作成 calc: 演算 (2変数関数, Monoid) unit: Monoid calc の単位元 (xe=ex=xを満たすe) """ 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): """第k要素をxに変え,更新を行う. 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())