結果
問題 | No.2704 L to R Graph |
ユーザー | hirayuu_yc |
提出日時 | 2024-03-12 15:26:57 |
言語 | PyPy3 (7.3.15) |
結果 |
AC
|
実行時間 | 851 ms / 3,000 ms |
コード長 | 7,363 bytes |
コンパイル時間 | 323 ms |
コンパイル使用メモリ | 82,480 KB |
実行使用メモリ | 143,360 KB |
最終ジャッジ日時 | 2024-09-29 22:20:25 |
合計ジャッジ時間 | 16,987 ms |
ジャッジサーバーID (参考情報) |
judge1 / judge3 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 49 ms
56,576 KB |
testcase_01 | AC | 44 ms
56,064 KB |
testcase_02 | AC | 45 ms
56,192 KB |
testcase_03 | AC | 65 ms
70,784 KB |
testcase_04 | AC | 66 ms
70,656 KB |
testcase_05 | AC | 64 ms
70,656 KB |
testcase_06 | AC | 64 ms
70,784 KB |
testcase_07 | AC | 66 ms
70,144 KB |
testcase_08 | AC | 851 ms
140,012 KB |
testcase_09 | AC | 785 ms
143,360 KB |
testcase_10 | AC | 762 ms
142,000 KB |
testcase_11 | AC | 677 ms
141,464 KB |
testcase_12 | AC | 669 ms
140,984 KB |
testcase_13 | AC | 689 ms
141,132 KB |
testcase_14 | AC | 672 ms
142,080 KB |
testcase_15 | AC | 662 ms
142,644 KB |
testcase_16 | AC | 673 ms
141,456 KB |
testcase_17 | AC | 671 ms
141,976 KB |
testcase_18 | AC | 668 ms
141,564 KB |
testcase_19 | AC | 686 ms
141,672 KB |
testcase_20 | AC | 702 ms
142,728 KB |
testcase_21 | AC | 779 ms
140,952 KB |
testcase_22 | AC | 673 ms
140,700 KB |
testcase_23 | AC | 689 ms
141,100 KB |
testcase_24 | AC | 673 ms
140,760 KB |
testcase_25 | AC | 710 ms
140,516 KB |
testcase_26 | AC | 785 ms
140,692 KB |
testcase_27 | AC | 587 ms
138,948 KB |
testcase_28 | AC | 553 ms
139,412 KB |
ソースコード
from array import array class UnionFind: def __init__(self,size:int)->None: self.siz=size self.tree=array("i",[-1]*size) def leader(self,pos:int)->int: ret=pos while self.tree[ret]>=0: ret=self.tree[ret] if pos!=ret: self.tree[pos]=ret return ret def same(self,u:int,v:int)->bool: return self.leader(u)==self.leader(v) def merge(self,u:int,v:int)->bool: u=self.leader(u) v=self.leader(v) if u==v: return False if self.tree[u]<self.tree[v]: u,v=v,u self.tree[v]+=self.tree[u] self.tree[u]=v return True def size(self,pos:int)->int: return -self.tree[self.leader(pos)] def groups(self)->list[list[int]]: mem=[[] for i in range(self.siz)] for i in range(self.siz): mem[self.leader(i)].append(i) ret=[] for i in mem: if len(i)!=0: ret.append(i) return ret class DisjointSparseTable: def __init__(self,default:list,op,e=None): self.size=len(default) self.op=op self.e=e self.table=default*max(1,(self.size-1).bit_length()) index=self.size for i in range(1,(self.size-1).bit_length()): for j in range(self.size): if ((j>>i)<<i)==j: continue if (j>>i)&1: self.table[j+index]=op(self.table[j-1+index],self.table[j+index]) else: pos=((j>>i)<<i)+((1<<i)-1)-(j&((1<<i)-1)) if pos<self.size: self.table[pos+index]=op(self.table[pos+index],self.table[pos+1+index]) index+=self.size def __getitem__(self,pos): if type(pos)==int: if not -self.size<=pos<self.size: raise IndexError if pos<0: return self.table[self.size+pos] else: return self.table[pos] left=pos.start if left==None: left=0 right=pos.stop if right==None: right=self.size if not 0<=left<=right<=self.size: raise IndexError if left==right: return self.e() if left+1==right: return self.table[left] pos=((left^(right-1)).bit_length()-1)*self.size return self.op(self.table[pos+left],self.table[pos+right-1]) from collections import deque class FoldableDeque: def __init__(self,op,e)->None: self.op=op self.e=e self.left=deque() self.leftop=deque([e()]) self.right=deque() self.rightop=deque([e()]) def append(self,v:any)->None: self.right.append(v) self.rightop.append(self.op(self.rightop[-1],v)) def appendleft(self,v:any)->None: self.left.append(v) self.leftop.append(self.op(v,self.leftop[-1])) def pop(self)->any: if len(self.right)==0: nl=[] while len(self.left)>0: nl.append(self.popleft()) self.leftop=deque([self.e()]) half=len(nl)//2 for i in nl[half:]: self.append(i) for i in nl[:half][::-1]: self.appendleft(i) self.rightop.pop() return self.right.pop() def popleft(self)->any: if len(self.left)==0: nr=[] while len(self.right)>0: nr.append(self.pop()) self.rightop=deque([self.e()]) half=len(nr)//2 for i in nr[half:]: self.appendleft(i) for i in nr[:half][::-1]: self.append(i) self.leftop.pop() return self.left.pop() def get_all(self): return self.op(self.leftop[-1],self.rightop[-1]) def __len__(self)->int: return len(self.left)+len(self.right) def __str__(self)->str: return str(list(self.left)[::-1])+str(list(self.right)) class FoldableQueue(FoldableDeque): def pop(self): assert False def popleft(self)->any: if len(self.left)==0: for i in reversed(self.right): self.appendleft(i) self.right=deque() self.rightop=deque([self.e()]) self.leftop.pop() return self.left.pop() from collections import deque def order_min(x,y): if srt[x]<srt[y]: return x return y def lca(u,v): u=srt[u] v=srt[v] if u>v: u,v=v,u return dst[u:v+1] INF=(1<<61)-1 N,L,R=map(int,input().split()) A=list(map(int,input().split())) uni=UnionFind(N) for i in range(N): A[i]-=1 uni.merge(i,A[i]) cycle=[0]*N giant=A[:] for i in range(30): giant=[giant[giant[i]] for i in range(N)] cycle_number=[-1]*N cycles_size=[0]*(N+1) for i in range(N): if cycle_number[giant[i]]!=-1: continue size=1 cycle_number[giant[i]]=0 pos=A[giant[i]] while cycle_number[pos]==-1: cycle_number[pos]=size pos=A[pos] size+=1 cycle[uni.leader(i)]=size cycles_size[size]=uni.size(i) for i in range(N): cycle[i]=cycle[uni.leader(i)] tree=[[] for i in range(N+1)] for i in range(N): if cycle_number[i]==-1: tree[A[i]].append(i) else: tree[N].append(i) root=[0]*(N+1) for i in tree[N]: root[i]=i deep=[0]*(N+1) tour=[] srt=[-1]*(N+1) vert=deque([N]) while vert: pos=vert.pop() if pos<0: tour.append(-pos-1) continue srt[pos]=len(tour) tour.append(pos) for i in tree[pos]: deep[i]=deep[pos]+1 root[i]=max(root[i],root[pos]) vert.append(-pos-1) vert.append(i) dps=[[] for i in range(N+1)] for i in range(N+1): if cycles_size[i]==0: continue dp=[INF]*cycles_size[i] seg=[INF]*(i*4) for j in range(i+1): lf=L*j ri=R*j+1 if ri-lf>=i: seg[1]=min(seg[1],j) break lf%=i ri%=i if lf>=ri: ri+=i lf+=i*2 ri+=i*2 while lf<ri: if lf&1: seg[lf]=min(seg[lf],j) lf+=1 if ri&1: ri-=1 seg[ri]=min(seg[ri],j) lf>>=1 ri>>=1 for j in range(i*2): pos=j+i*2 while pos>0: dp[j%i]=min(dp[j%i],seg[pos]) pos>>=1 que=FoldableQueue(min,lambda:INF) for j in range(R,L-1,-1): que.append(dp[(-j)%i]) for j in range(i,cycles_size[i]): dp[j]=que.get_all()+1 que.popleft() que.append(dp[max(j+1-L,(j+1-L)%i)]) for j in range(cycles_size[i]): if dp[j]>=INF: dp[j]=-1 dps[i]=dp dst=DisjointSparseTable(tour,order_min) Q=int(input()) for i in range(Q): S,T=map(int,input().split()) S-=1 T-=1 if not uni.same(S,T): print(-1) continue cyc=cycle[root[S]] dist=deep[S]-deep[T]+(cycle_number[root[T]]-cycle_number[root[S]])%cyc if cycle_number[T]==-1: if lca(S,T)!=T: print(-1) continue ans=(dist+R-1)//R if L*ans<=dist<=R*ans: print(ans) else: print(-1) continue print(dps[cyc][dist])