セグメントツリー を使用して this 問題を解決していますが、制限時間エラーが発生します。以下は、範囲最小クエリの生のコードです。コードでmin
をmax
に変更することで、上記の問題を解決できます。コードのパフォーマンスを改善する方法がわかりません。パフォーマンスの問題について教えてください。
t = [None] * 2 * 7 # n is length of list
def build(a, v, start, end):
'''
A recursive function that constructs Segment Tree for list a.
v is the starting node
start and end are the index of array
'''
n = len(a)
if start == end:
t[v] = a[start]
else:
mid = (start + end) / 2
build(a, v * 2, start, mid) # v*2 is left child of parent v
# v*2+1 is the right child of parent v
build(a, v * 2 + 1, mid + 1, end)
t[v] = min(t[2 * v], t[2 * v + 1])
return t
print build([18, 17, 13, 19, 15, 11, 20], 1, 0, 6)
inf = 10**9 + 7
def range_minimum_query(node, segx, segy, qx, qy):
'''
returns the minimum number in range(qx,qy)
segx and segy represent the segment index
'''
if qx > segy or qy < segx: # query out of range
return inf
Elif segx >= qx and segy <= qy: # query range inside segment range
return t[node]
else:
return min(range_minimum_query(node * 2, segx, (segx + segy) / 2, qx, qy), range_minimum_query(node * 2 + 1, ((segx + segy) / 2) + 1, segy, qx, qy))
print range_minimum_query(1, 1, 7, 1, 3)
# returns 13
これを繰り返し実装できますか?
まず、Pythonを使用している場合、おそらく採点者に合格することはありません。ここで過去のすべてのソリューションのステータスを見ると、 http://www.spoj.com/status/GSS1/start= 、受け入れられたほとんどすべてのソリューションが次のように記述されていることがわかります。 C++。 C++を使用する以外に選択肢はないと思います。制限時間が0.115秒から0.230秒であることに注意してください。これは「C/C++専用」の時間制限です。他の言語で解決策を受け入れる問題の場合、制限時間は1秒のような「ラウンド」数になります。 Pythonは、このタイプの環境ではC++よりも約2〜4倍遅くなります。
次に、コードが実際にセグメントツリーを構築しているかどうかはわかりません。具体的には、なぜこの行があるのかわかりません。
_t[v]=min(t[2*v],t[2*v+1])
_
セグメントツリーのノードには子の合計が格納されていると確信しているので、実装がほぼ正しい場合は、代わりに次のように読み取る必要があると思います。
_t[v] = t[2*v] + t[2*v+1]
_
コードが「正しい」場合、間隔の合計を保存していなくても、範囲_[x_i, y_i]
_内の最大間隔の合計をどのように見つけているのか疑問に思います。
第3に、セグメントツリーを繰り返し実装できます。これがC++のチュートリアルです: http://codeforces.com/blog/entry/18051 。
最後に、セグメントツリーがこの問題にどのように役立つのかわかりません。セグメントツリーを使用すると、log(n)
の範囲の合計をクエリできます。この問題は、任意の範囲の可能な最大合計を要求します。 「範囲最小クエリ」または「範囲最大クエリ」を可能にするセグメントツリーについて聞いたことがありません。
単純な解決策は、1つのクエリに対してO(n ^ 3)(n ^ 2の可能なすべての開始点と終了点を試し、O(n)操作)で合計を計算する)です。セグメントツリーを使用すると、O(n)の代わりにO(log(n))で合計を取得できます)。 、N = 50000では機能しません。
代わりに、クエリごとにO(n)で実行されるこれを確認する必要があると思います: http://www.geeksforgeeks.org/largest-sum-contiguous-subarray / 。C/ C++で記述し、1人のコメント提供者が提案したようにIOで効率的にします。
多くの制限を回避できるので、ジェネレーターを試してみることができます。ただし、パフォーマンスの問題を明確に示すデータセットを提供していません。問題のあるデータセットを提供できますか?
ここで試すことができます:
t=[None]*2*7
inf=10**9+7
def build_generator(a, v, start, end):
n = len(a)
if start == end:
t[v] = a[start]
else:
mid = (start + end) / 2
next(build_generator(a, v * 2, start, mid))
next(build_generator(a, v * 2 + 1, mid + 1, end))
t[v] = min(t[2 * v], t[2 * v + 1])
yield t
def range_minimum_query_generator(node,segx,segy,qx,qy):
if qx > segy or qy < segx:
yield inf
Elif segx >= qx and segy <= qy:
yield t[node]
else:
min_ = min(
next(range_minimum_query_generator(node*2,segx,(segx+segy)/2,qx,qy)),
next(range_minimum_query_generator(node*2+1,((segx+segy)/2)+1,segy,qx,qy))
)
yield min_
next(build_generator([18,17,13,19,15,11,20],1,0,6))
value = next(range_minimum_query_generator(1, 1, 7, 1, 3))
print(value)
編集
実際、それでは問題が解決しない場合があります。再帰制限を回避する別の方法があります(ジェネレーターに関するチュートリアルでD. Beazleyが説明しているように- https://www.youtube.com/watch?v=D1twn9kLmYg&t=9588s タイムコード2h00前後)