結果

問題 No.1641 Tree Xor Query
ユーザー titiatitia
提出日時 2021-08-06 22:41:58
言語 PyPy3
(7.3.15)
結果
AC  
実行時間 282 ms / 5,000 ms
コード長 3,867 bytes
コンパイル時間 174 ms
コンパイル使用メモリ 81,852 KB
実行使用メモリ 123,288 KB
最終ジャッジ日時 2023-10-17 04:11:17
合計ジャッジ時間 3,198 ms
ジャッジサーバーID
(参考情報)
judge13 / judge12
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 34 ms
53,568 KB
testcase_01 AC 35 ms
53,568 KB
testcase_02 AC 36 ms
53,568 KB
testcase_03 AC 36 ms
53,568 KB
testcase_04 AC 37 ms
53,568 KB
testcase_05 AC 38 ms
53,568 KB
testcase_06 AC 37 ms
53,568 KB
testcase_07 AC 36 ms
53,568 KB
testcase_08 AC 35 ms
53,568 KB
testcase_09 AC 35 ms
53,568 KB
testcase_10 AC 36 ms
53,568 KB
testcase_11 AC 40 ms
53,568 KB
testcase_12 AC 37 ms
53,568 KB
testcase_13 AC 248 ms
109,420 KB
testcase_14 AC 243 ms
109,412 KB
testcase_15 AC 122 ms
78,464 KB
testcase_16 AC 165 ms
79,972 KB
testcase_17 AC 163 ms
79,864 KB
testcase_18 AC 123 ms
78,540 KB
testcase_19 AC 121 ms
77,004 KB
testcase_20 AC 282 ms
123,288 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

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)
            
        
0