結果
問題 | No.833 かっこいい電車 |
ユーザー |
👑 ![]() |
提出日時 | 2021-03-13 04:24:10 |
言語 | PyPy3 (7.3.15) |
結果 |
AC
|
実行時間 | 701 ms / 2,000 ms |
コード長 | 8,836 bytes |
コンパイル時間 | 167 ms |
コンパイル使用メモリ | 82,688 KB |
実行使用メモリ | 114,048 KB |
最終ジャッジ日時 | 2024-10-14 16:55:07 |
合計ジャッジ時間 | 13,042 ms |
ジャッジサーバーID (参考情報) |
judge5 / judge4 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 2 |
other | AC * 30 |
ソースコード
class Lazy_Evaluation_Tree():def __init__(self,L,calc,unit,op,comp,id,index):"""calcを演算,opを作用とするリストLのSegment Treeを作成calc:演算unit:モノイドcalcの単位元 (xe=ex=xを満たすe)op:作用素comp:作用素の合成id:恒等写像[条件] M:Monoid,F={f:F x M→ M:作用素}に対して,以下が成立する.Fは恒等写像 id を含む.つまり,任意の x in M に対して id(x)=xFは写像の合成に閉じている.つまり,任意の f,g in F に対して, comp(f,g) in F任意の f in F, x,y in M に対して,f(xy)=f(x)f(y)である.[注記]作用素は左から掛ける.更新も左から."""self.calc=calcself.unit=unitself.op=opself.comp=compself.id=idself.index=indexN=len(L)d=max(1,(N-1).bit_length())k=1<<dself.data=[unit]*k+L+[unit]*(k-len(L))self.lazy=[self.id]*(2*k)self.N=kself.depth=dfor i in range(k-1,0,-1):self.data[i]=calc(self.data[i<<1],self.data[i<<1|1])def _eval_at(self,m):if self.lazy[m]==self.id:return self.data[m]return self.op(self.lazy[m],self.data[m])#配列の第m要素を下に伝搬def _propagate_at(self,m):self.data[m]=self._eval_at(m)if m<self.N and self.lazy[m]!=self.id:self.lazy[m<<1]=self.comp(self.lazy[m],self.lazy[m<<1])self.lazy[m<<1|1]=self.comp(self.lazy[m],self.lazy[m<<1|1])self.lazy[m]=self.id#配列の第m要素より上を全て伝搬def _propagate_above(self,m):H=m.bit_length()for h in range(H-1,0,-1):self._propagate_at(m>>h)#配列の第m要素より上を全て再計算def _recalc_above(self,m):while m>1:m>>=1self.data[m]=self.calc(self._eval_at(m<<1),self._eval_at(m<<1|1))def get(self,k):index=self.indexm=k-index+self.Nself._propagate_above(m)self.data[m]=self._eval_at(m)self.lazy[m]=self.idreturn self.data[m]#作用def operate(self,From,To,alpha,left_closed=True,right_closed=True):index=self.indexL=(From-index)+self.N+(not left_closed)R=(To-index)+self.N+(right_closed)L0=R0=-1X,Y=L,R-1while X<Y:if X&1:L0=max(L0,X)X+=1if Y&1==0:R0=max(R0,Y)Y-=1X>>=1Y>>=1L0=max(L0,X)R0=max(R0,Y)self._propagate_above(L0)self._propagate_above(R0)while L<R:if L&1:self.lazy[L]=self.comp(alpha,self.lazy[L])L+=1if R&1:R-=1self.lazy[R]=self.comp(alpha,self.lazy[R])L>>=1R>>=1self._recalc_above(L0)self._recalc_above(R0)def update(self,k,x):""" 第k要素をxに変更する."""index=self.indexm=k-index+self.Nself._propagate_above(m)self.data[m]=xself.lazy[m]=self.idself._recalc_above(m)def product(self,From,To,left_closed=True,right_closed=True):index=self.indexL=(From-index)+self.N+(not left_closed)R=(To-index)+self.N+(right_closed)L0=R0=-1X,Y=L,R-1while X<Y:if X&1:L0=max(L0,X)X+=1if Y&1==0:R0=max(R0,Y)Y-=1X>>=1Y>>=1L0=max(L0,X)R0=max(R0,Y)self._propagate_above(L0)self._propagate_above(R0)vL=vR=self.unitwhile L<R:if L&1:vL=self.calc(vL,self._eval_at(L))L+=1if R&1:R-=1vR=self.calc(self._eval_at(R),vR)L>>=1R>>=1return self.calc(vL,vR)def all_product(self):return self.product(1,self.N,1)#リフレッシュdef refresh(self):for m in range(1,2*self.N):self.data[m]=self._eval_at(m)if m<self.N and self.lazy[m]!=self.id:self.lazy[m<<1]=self.comp(self.lazy[m],self.lazy[m<<1])self.lazy[m<<1|1]=self.comp(self.lazy[m],self.lazy[m<<1|1])self.lazy[m]=self.iddef __getitem__(self,k):return self.get(k)def __setitem__(self,k,x):self.update(k,x)class Binary_Indexed_Tree():def __init__(self,L,calc,unit,inv,index=1):"""calcを演算とするN項のBinary Indexed Treeを作成calc:演算(2変数関数,群)unit:群calcの単位元(xe=ex=xを満たすe)inv:群calcの逆元(1変数関数)"""self.calc=calcself.unit=unitself.inv=invself.index=indexN=len(L)d=max(1,(N-1).bit_length())k=2**dX=[None]+[unit]*kself.num=kself.depth=dif L:for i in range(len(L)):p=i+1while p<=k:X[p]=self.calc(X[p],L[i])p+=p&(-p)self.data=Xdef index_number(self,k,index=1):"""第k要素の値を出力する.k:数列の要素index:先頭の要素の番号"""return self.sum(k,k,index)def add(self,k,x,index=1,right=False):"""第k要素にxを左から加え,更新を行う.k:数列の要素x:更新後の値index:先頭の要素の番号right:「左から」が「右から」になる"""p=k+(1-index)while p<=self.num:if right==False:#左からself.data[p]=self.calc(x,self.data[p])else:#右からself.data[p]=self.calc(self.data[p],x)p+=p&(-p)def update(self,k,x,index=1,right=False):"""第k要素をxに変え,更新を行う.k:数列の要素x:更新後の値"""a=self.index_number(k,index)if right==False:#左からy=self.calc(x,self.inv(a))else:#右からy=self.calc(self.inv(a),x)self.add(k,y,index,right)def sum(self,From,To,index=1):"""第From要素から第To要素までの総和を求める.※From!=1を使うならば,群でなくてはならない.From:始まりTo:終わりindex:先頭の要素の番号"""alpha=max(1,From+(1-index))beta=min(self.num,To+(1-index))if alpha==1:return self.__section(beta)else:return self.calc(self.inv(self.__section(alpha-1)),self.__section(beta))def __section(self,To):S=self.unitx=Towhile x>0:S=self.calc(self.data[x],S)x-=x&(-x)return Sdef all_sum(self):return self.data[-1]def __getitem__(self,index):if isinstance(index,int):return self.index_number(index,self.index)else:return [self.index_number(t,self.index) for t in index]def __setitem__(self,index,val):self.update(index,val,self.index)#================================================import sysfrom operator import add,neginput=sys.stdin.readlinewrite=sys.stdout.writeN,Q=map(int,input().split())A=list(map(int,input().split()))L=Lazy_Evaluation_Tree(list(range(1,N+1)),max,0,lambda a,x:a,lambda a,b:a,-1,1)R=Lazy_Evaluation_Tree(list(range(1,N+1)),max,0,lambda a,x:a,lambda a,b:a,-1,1)S=Binary_Indexed_Tree(A,add,0,neg,1)X=[]Connect=[0]*Nfor _ in range(Q):t,x=map(int,input().split())if t==1:if Connect[x]==0:l=L.get(x)r=R.get(x+1)L.operate(l,r,l)R.operate(l,r,r)Connect[x]=1elif t==2:if Connect[x]==1:l=L.get(x)r=R.get(x+1)R.operate(l,x,x)L.operate(x+1,r,x+1)Connect[x]=0elif t==3:S.add(x,1,1)else:l=L.get(x)r=R.get(x)X.append(S.sum(l,r,1))write("\n".join(map(str,X)))