結果
| 問題 |
No.1641 Tree Xor Query
|
| コンテスト | |
| ユーザー |
titia
|
| 提出日時 | 2021-08-06 22:41:58 |
| 言語 | PyPy3 (7.3.15) |
| 結果 |
AC
|
| 実行時間 | 298 ms / 5,000 ms |
| コード長 | 3,867 bytes |
| コンパイル時間 | 243 ms |
| コンパイル使用メモリ | 82,364 KB |
| 実行使用メモリ | 123,572 KB |
| 最終ジャッジ日時 | 2024-09-17 02:53:52 |
| 合計ジャッジ時間 | 3,303 ms |
|
ジャッジサーバーID (参考情報) |
judge1 / judge4 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 18 |
ソースコード
import sys
input = sys.stdin.readline
N,Q=map(int,input().split())
C=[0]+list(map(int,input().split()))
E=[[] for i in range(N+1)]
for i in range(N-1):
a,b=map(int,input().split())
#a-=1
#b-=1
E[a].append(b)
E[b].append(a)
# 木のHL分解+LCA
N+=1 # ROOTの親の点を一つ余計に見るため、総ノード数を一つ増やしておく
ROOT=1
QUE=[ROOT]
Parent=[-1]*(N+1)
Parent[ROOT]=N # ROOTの親を定めておく.
TOP_SORT=[] # トポロジカルソート
while QUE: # トポロジカルソートと同時に親を見つける
x=QUE.pop()
TOP_SORT.append(x)
for to in E[x]:
if Parent[to]==-1:
Parent[to]=x
QUE.append(to)
Children=[1]*(N+1)
for x in TOP_SORT[::-1]: #(自分を含む)子ノードの数を調べる
Children[Parent[x]]+=Children[x]
USE=[0]*N
Group=[i for i in range(N+1)]
for x in TOP_SORT: # HL分解によるグループ分け
USE[x]=1
MAX_children=0
select_node=0
for to in E[x]:
if USE[to]==0 and Children[to]>MAX_children:
select_node=to
MAX_children=Children[to]
for to in E[x]:
if USE[to]==0 and to==select_node:
Group[to]=Group[x]
def LCA(a,b): # HL分解を利用してLCAを求める
while Group[a]!=Group[b]:
if Children[Parent[Group[a]]]<Children[Parent[Group[b]]]:
a=Parent[Group[a]]
else:
b=Parent[Group[b]]
if Children[a]>Children[b]:
return a
else:
return b
# 以下、セグ木に乗せる場合
def PATH(a,b): # HL分解を利用してa,b間のpathを出力する. LCAとやることは同じ. log個の閉区間に分割する.
while Group[a]!=Group[b]:
if Children[Parent[Group[a]]]<Children[Parent[Group[b]]]:
yield (a,Group[a])
a=Parent[Group[a]]
else:
yield (b,Group[b])
b=Parent[Group[b]]
if Children[a]>Children[b]:
yield (b,a)
else:
yield (a,b)
END_node=[-1]*(N+1) # HL分解したときの終点ノード
select_child=[[] for i in range(N+1)] # 子グループの代表ノード
for x in TOP_SORT:
END_node[Group[x]]=x
if Group[Parent[x]]!=Group[x]:
select_child[Group[Parent[x]]].append(x)
def children_PATH(x): # HL分解を利用してx以下のchildren全てをpathとして出力する.
Q=[x]
while Q:
x=Q.pop()
yield (END_node[Group[x]],x)
for to in select_child[Group[x]]:
if Children[Parent[to]]<=Children[x]:
Q.append(to)
SEG_to_NODE=sorted(list(range(N)),key=lambda x:((Group[x]+1)<<30)+Children[x]) # Segment treeに載せるため, Groupごとに並べる.子ノードが少ないものが先に来るようにしている.
NODE_to_SEG=[-1]*N #その逆関数. NODE_to_SEG[ind]をセグ木に乗せる.
for ind,x in enumerate(SEG_to_NODE):
NODE_to_SEG[x]=ind
seg_el=1<<((N+1).bit_length()) # Segment treeの台の要素数
SEG=[0]*(2*seg_el) # 1-indexedなので、要素数2*seg_el.Segment treeの初期値で初期化
def getvalue(n,seg_el): # 一点の値を取得
i=n+seg_el
ANS=0
ANS^=SEG[i]
i>>=1# 子ノードへ
while i!=0:
ANS^=SEG[i]
i>>=1
return ANS
def updates(l,r,x):
L=l+seg_el
R=r+seg_el
while L<R:
if L & 1:
SEG[L]^=x
L+=1
if R & 1:
R-=1
SEG[R]^=x
L>>=1
R>>=1
for x in TOP_SORT[::-1][:-1]:
C[Parent[x]]^=C[x]
for i in range(1,N):
updates(NODE_to_SEG[i],NODE_to_SEG[i]+1,C[i])
for queries in range(Q):
c,x,y=map(int,input().split())
if c==2:
print(getvalue(NODE_to_SEG[x],seg_el))
else:
for l,r in PATH(x,1):
updates(NODE_to_SEG[l],NODE_to_SEG[r]+1,y)
titia