''' class UnionFind: def __init__(self,N,label=None,f=None,weighted=False,rollback=False): self.N=N self.parents=[None]*self.N self.size=[1]*self.N self.roots={i for i in range(self.N)} self.label=label if self.label!=None: self.label=[x for x in label] self.f=f self.weighted=weighted if self.weighted: self.weight=[0]*self.N self.rollback=rollback if self.rollback: self.operate_list=[] self.operate_set=[] def Find(self,x): stack=[] while self.parents[x]!=None: stack.append(x) x=self.parents[x] if not self.rollback: if self.weighted: w=0 for y in stack[::-1]: self.parents[y]=x w+=self.weight[y] self.weight[y]=w else: for y in stack[::-1]: self.parents[y]=x return x def Union(self,x,y,w=None): root_x=self.Find(x) root_y=self.Find(y) if self.rollback: self.operate_list.append([]) self.operate_set.append([]) if root_x==root_y: if self.weighted: if self.weight[y]-self.weight[x]==w: return True else: return False else: if self.size[root_x]d: dist[i][j]=d if route_restoration: parents[i][j]=i if not self.directed and dist[j][i]>d: dist[j][i]=d if route_restoration: parents[j][i]=j for k in range(self.V): for i in range(self.V): for j in range(self.V): if dist[i][j]>dist[i][k]+dist[k][j]: dist[i][j]=dist[i][k]+dist[k][j] if route_restoration: parents[i][j]=parents[k][j] for i in range(self.V): if dist[i][i]<0: for j in range(self.V): if dist[i][j]!=self.inf: dist[i][j]=-self.inf if route_restoration: for i in range(self.V): if dist[i][i]==0: parents[i][i]=None return dist,parents else: return dist def Kruskal(self,maximize=False,spanning_tree=False): UF=UnionFind(self.V) sorted_edges=sorted(self.edges if self.weighted else [(x,y,1) for x,y in self.edges],key=lambda tpl:tpl[2],reverse=maximize) if spanning_tree: st=[] else: cost=0 for x,y,d in sorted_edges: if not UF.Same(x,y): UF.Union(x,y) if spanning_tree: st.append((x,y,d)) else: cost+=d return st if spanning_tree else cost ''' def Inversion_Number(lst,weight=False,weakly=False): compress,decompress=Compress(lst) compressed_lst=[compress[x] for x in lst] N=len(compress) if not weight: weight=[1]*len(lst) ST=Segment_Tree(N,lambda x,y:x+y,0) inversion_number=0 for c,x in zip(weight,compressed_lst): inversion_number+=ST.Fold(x if weakly else x+1,N)*c ST[x]+=c return inversion_number def Compress(lst): decomp=sorted(list(set(lst))) comp={x:i for i,x in enumerate(decomp)} return comp,decomp class Segment_Tree: def __init__(self,N,f,e,lst=None,dynamic=False): self.f=f self.e=e self.N=N if dynamic: self.segment_tree=defaultdict(lambda:self.e) else: if lst==None: self.segment_tree=[self.e]*2*self.N else: assert len(lst)<=self.N self.segment_tree=[self.e]*self.N+[x for x in lst]+[self.e]*(N-len(lst)) for i in range(self.N-1,0,-1): self.segment_tree[i]=self.f(self.segment_tree[i<<1],self.segment_tree[i<<1|1]) def __getitem__(self,i): if type(i)==int: if -self.N<=i<0: return self.segment_tree[i+self.N*2] elif 0<=i1: i>>= 1 self.segment_tree[i]=self.f(self.segment_tree[i<<1],self.segment_tree[i<<1|1]) def Build(self,lst): for i,x in enumerate(lst,self.N): self.segment_tree[i]=x for i in range(self.N-1,0,-1): self.segment_tree[i]=self.f(self.segment_tree[i<<1],self.segment_tree[i<<1|1]) def Fold(self,L=None,R=None): if L==None: L=self.N else: L+=self.N if R==None: R=self.N*2 else: R+=self.N vL=self.e vR=self.e while L>=1 R>>=1 return self.f(vL,vR) def Fold_Index(self,L=None,R=None): if L==None: L=self.N else: L+=self.N if R==None: R=self.N*2 else: R+=self.N if L==R: return None x=self.Fold(L-self.N,R-self.N) while L>=1 R>>=1 while i>=1 r>>=1 if f(self.f(vl,vr)): return self.N v=self.e while True: while L%2==0: L>>=1 vv=self.f(v,self.segment_tree[L]) if f(vv): v=vv L+=1 else: while L>=1 r>>=1 if f(self.f(vl,vr)): return 0 v=self.e while True: R-=1 while R>1 and R%2: R>>=1 vv=self.f(self.segment_tree[R],v) if f(vv): v=vv else: while R