【30分】実装してみる・問題を解いてみる
(i & -i)でiの最末尾の1を表せることを自分で考え出せる人天才すぎる。
""" 部分和の計算と要素の更新の効率化に用いる Binary Indexed Tree 別名 Fenwick Tree(フェニック木) Segment Treeの機能を制限し、単純化したものと言えそう BIT[1]=BIT[0+1]=init_list[0] BIT[2]=BIT[1+1]=init_list[0]+init_list[1] BIT[3]=BIT[2+1]=init_list[2] BIT[4]=BIT[3+1]=init_list[0]+・・・+init_list[3] BIT[5]=BIT[4+1]=init_list[4] BIT[6]=BIT[5+1]=init_list[4]+init_list[5] BIT[7]=BIT[6+1]=init_list[6] BIT[8]=BIT[7+1]=init_list[0]+・・・+init_list[7] """ class BIT: #segtree:入力のリスト=treeの葉 #fenwick:入力のリスト=treeの葉 場所によっては同じ #葉によって担当する区間の長さが異なる def __init__(self,n): self.n=n self.tree=[0]*(n+1) #init_list[i]+=x def add(self,i,x): #treeは1-indexed, 対象のリストは0-indexed i+=1 while i<=self.n: self.tree[i]+=x """ iの最後の1のビットは、そのノードが表現する区間のサイズを表す iの負の数を2進数で表すには 1. すべてのビットを反転させる 2. 1を加算する e.g.) 0110(6) 1. 1001 2. 1010(-6) これを利用すると iの最後の1のビットは(i & -i)で表せる 更新すべき区間はノード番号に区間の長さを足すと求められる e.g.) init_list[2]が更新された(tree[3]に対応) まずtree[3]を更新 3の最後の1のビットは1(3&-3によって求まる) i+=(3&-3) : i+=1 ->i=4 次にtree[4]を更新 4の最後の1のビットは4(4&-4によって求まる) i+=(4&-4) : i+=4 -> i=8 次にtree[8]を更新 8の最後の1のビットは8 ・ ・ ・ このような手順を踏むことで,iが区間に含まれるノードを辿れる 実際,init_list[2]が含まれているノードは3,4,8,・・・ BIT[3]=BIT[2+1]=init_list[2] BIT[4]=BIT[3+1]=init_list[0]+・・・+init_list[3] BIT[8]=BIT[7+1]=init_list[0]+・・・+init_list[7] """ i+=(i & -i) #init_list[0]+init_list[1]+・・・init_list[i] def sum(self,i): #treeは1-indexed, 対象のリストは0-indexed i+=1 s=0 while i>0: s+=self.tree[i] """ 次に足すべき区間はノード番号から区間の長さを引くことで求まる """ i-=(i & -i) return s #init_list[l]+・・・+init_list[r-1] def sumlr(self,l,r): return self.sum(r-1)-self.sum(l-1) n,q=map(int,input().split()) a=list(map(int,input().split())) bit=BIT(n) for i in range(n): bit.add(i,a[i]) for _ in range(q): b,c,d=map(int,input().split()) if(b==0): bit.add(c,d) else: print(bit.sumlr(c,d))
【20分100分】別のフェニック木問題を自力でACしてみる
解説プラス先人のコード読んでなんとかAC。フェニック木の使い道がほんの少しわかった。
もう一問だけやってみる。2問目では必要なかった座標圧縮が必要。modの知識も足りてなかった。泣いた。そこそこ分かりやすいコードを書けた気がする。
総括
難しかった。頭痛くなった。
classとかselfとか全然理解してないまま書いてる。終わってる。