結果
問題 | No.2248 max(C)-min(C) |
ユーザー |
👑 ![]() |
提出日時 | 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 |
ソースコード
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=calcself.unit=unitN=len(L); self.n=Nd=max(1,(N-1).bit_length())k=1<<dself.data=data=[unit]*k+L+[unit]*(k-len(L))self.N=kself.depth=dfor 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.Ndata=self.data; calc=self.calcdata[m]=xwhile m>1:m>>=1data[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.unitvR=self.unitdata=self.data; calc=self.calcwhile L<R:if L&1:vL=calc(vL, data[L])L+=1if R&1:R-=1vR=calc(data[R], vR)L>>=1R>>=1return 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): True0<=left<=N"""assert 0<=left<=self.N,"添字が範囲外"assert cond(self.unit),"単位元が条件を満たさない."if left==self.N:return self.Nleft+=self.Nsm=self.unitcalc=self.calc; data=self.datafirst=Truewhile first or (left & (-left))!=left:first=Falsewhile left%2==0:left>>=1if not cond(calc(sm, data[left])):while left<self.N:left<<=1if cond(calc(sm, data[left])):sm=calc(sm, data[left])left+=1return left-self.Nsm=calc(sm, data[left])left+=1return self.Ndef 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): True0<=right<=N"""assert 0<=right<=self.N,"添字が範囲外"assert cond(self.unit),"単位元が条件を満たさない."if right==0:return 0right+=self.Nsm=self.unitcalc=self.calc; data=self.datafirst=1while first or (right & (-right))!=right:first=0right-=1while right>1 and right&1:right>>=1if not cond(calc(data[right], sm)):while right<self.N:right=2*right+1if cond(calc(data[right], sm)):sm=calc(data[right], sm)right-=1return right+1-self.Nsm=calc(data[right], sm)return 0def __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, insortclass Sorted_Multiset:BUCKET_RATIO=50REBUILD_RATIO=170def __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)returndef __build(self, A=None):if A is None:A=list(self)self.N=N=len(A)K=1while self.BUCKET_RATIO*K*K<N:K+=1self.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 adef __reversed__(self):for A in reversed(self.list):for a in reversed(A):yield adef __len__(self):return self.Ndef __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 Aelse:return Adef __contains__(self, x):if self.N==0:return FalseA=self.__find_bucket(x)i=bisect_left(A,x)return i!=len(A) and A[i]==xdef add(self, x):if self.N==0:self.list=[[x]]self.N+=1returnA=self.__find_bucket(x)insort(A, x)self.N+=1if len(A)>len(self.list)*self.REBUILD_RATIO:self.__build()def discard(self, x):if self.N==0:return FalseA=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-=1if len(A)==0:self.__build()return Truedef remove(self, x):if not self.discard(x):raise KeyError(x)#=== get, popdef __getitem__(self, index):if index<0:index+=self.Nif 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-=1if len(A)==0:self.__build()return valuedef 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-=1if len(A)==0:self.__build()return value#=== previous, nextdef previous(self, value, mode=False):""" S にある value 未満で最大の要素を返す (存在しない場合は None)mode: True のときは "未満" が "以下" になる."""if self.N==0:return Noneif 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 Noneif 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)]#=== countdef less_count(self, value, equal=False):""" a < value となる S の元 a の個数を求める.equal=True ならば, a < value が a <= value になる."""count=0if 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 countdef 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 Truedef 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#=== indexdef index(self, value):index=0for A in self.list:if A[-1]>value:i=bisect_left(A, value)if A[i]==value:return index+ielse: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]*Nans=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:breakremain[i]-=1ans=min(ans, E.get_max()-E.get_min())return ans#==================================================print(solve())