質問の意味:
マトリックスが与えられると、行列はポイント数を有し、各点は、最大ブロックの箱入り生体重中点のいくつかのその点を見つけるために、正または負の重み付け値を有しています。
ソリューション:
離散的な水平および垂直座標は、この問題は簡単に最大とマトリックス上のサブ行列を求める問題に変換されます。
共通のn×n個の行列のサブ行列、および$(N ^ 3)Oの$、上下端DP列挙として解釈される最大
しかし、この質問は、スパース行列、n個の* nの行列のみO(n)のポイントは、$ O(N ^ 2logn)$ソリューションが必要です。
下端点に最大セグメントツリーメンテナンス間隔と各列挙で、上下端を列挙することで、下端値上の全ての点に対して権利がツリーラインに更新される正解、各更新LOGN
点の数はO(N)であるので、その結果、列挙エンドポイント更新セグメントツリーの各合計時間複雑さ$ OとO(N)、(N ^ 2logn)$まで
間隔と最大で以下の情報を保存のセグメントツリーのノード:合計(和)、maxsum(最大サブセグメント)、Lmaxと(及び最大のプレフィックス)、(最大及びサフィックス)のRmaxが
#include <ビット/ STDC ++ H> 使用して 名前空間STDを、 typedefの長い 長いLL。 typedefのペア < int型、LL> P; const int型 M = 2E3 + 5 。 constの LL MOD = 998244353 ; constの LL LINF = 0x3f3f3f3f3f3f3f3f 。 #define LS(RT << 1) の#define RS(RT << 1 | 1) LLのGCD(LL、LL b)は{ 戻り B?GCD(B、%のB)。} 構造体ノード{ int型のL、R。 LLの合計値、lsmx、rsmx、MX。 } TR [M* 4 ]; LL A [M]; LLプリ、ANS; // 右端と先頭からサブセグメントの最大を事前検索スペース前、ANS現在の最大 空隙押し上げ(INT RT) { TR [RT] .SUM = TR [LS] + .SUM TR [RS] .SUM; TR [RT] .lsmx = MAX(TR [LS] + .SUM TR [RS] .lsmx、TR [LS] .lsmx); TR [RT]。 rsmx = MAX(TR [RS] + .SUM TR [LS] .rsmx、TR [RS] .rsmx); TR [RT] .MX = MAX(MAX(TR [LS] .MX、TR [RS] .MX )、TR [LS] + .rsmx TR [RS] .lsmx); } ボイドビルド(INT RT、int型の L、INT R&LT) { TR [RT] .L = L、TR [RT] .R =R; もし(L == R) { TR [RT] .SUM + = [L]。 TR [RT] .lsmx + = [L]。 TR [RT] .rsmx + = [L]。 TR [RT] .MX + = [L]。 返します。 } INT半ば=(L + R)>> 1 。 (LS、L、ミッド)を構築。 構築(RS、ミッド + 1 、R); 突き上げ(RT)。 } ボイド更新(int型 RT、int型の L、int型の R、int型のPOS、LLのV) { もし(L == R) { TR [RT] .SUM + = V。 TR [RT] .lsmx + = V。 TR [RT] .rsmx + = V。 TR [RT] .MX + = V。 返します。 } INT半ば=(L + R)>> 1 。 もし(POS <= MID) 更新(LS、L、中間、POS、V)。 他の 更新(RS、ミッド + 1 、R、POS、V); 突き上げ(RT)。 } 空のクエリ(int型 RT、int型 QL、int型QR) { 場合(QL <= TR [RT] .L && TR [RT] .R <= QR) { ANS = MAX(ANS、TR [RT] .MX)。 ANS = MAX(ANS、プリ+のTR [RT] .lsmx)。 予備 = MAX(プリ+ TR、[RT] .SUM TR [RT] .rsmx)。 返します。 } INT半ば=(TR [RT] .L + TR [RT] .R)>> 1 。 もし(QL <= MID) { クエリ(LS、QL、QR)。 } であれば(QR> MID) { クエリ(RS、QL、QR)。 } } int型のn; int型Q; LL X [M]、Y [M]、ヴァル[M]。 LLのXID [M]、YID [M]。 int型xsz、YSZ。 ベクター <P> VEの[M]。 INT のmain() { int型_。 scanf関数(" %のD "、&_)。 一方、(_-- ) { scanf関数(" %のD "、&N) 以下のために(int型 i = 1 ; iが<= N; iは++ ) { scanf関数(" %LLD%LLD%LLD "、およびX [i]は、&Y [i]は、&ヴァル[I])。= X [i]は、 YID [I] = Y [I]を、 } ソート(YID + 1、YID + 1個の + N)。 ソート(XID + 1、XID + 1個の + N)。 xsz =ユニーク(XID + 1、XID + 1個の + N) - (XID + 1 )。 YSZ =ユニーク(YID + 1、YID + 1個の + N) - (YID + 1 )。 以下のために(int型 I = 1 ; I <= YSZ; iは++ ) { VEの[I] .clear(); } のために(int型 i = 1 ; iがn = <; iは++ ) { int型XI、YI。 XI = LOWER_BOUND(XID + 1、XID + 1 + xsz、X [I]) - XID。 YI = LOWER_BOUND(YID + 1、YID + 1 + YSZ、Y [I]) - YID。 VEの[イル] .push_back(make_pair(XI、ヴァル[I]))。 } ANS = 0 。 以下のための(int型私は= 1 ; I <= YSZ;私は++)//下边界 { memsetの(TR、0、はsizeof TR)。 用(int型 J = I; J> = 1 ; j--)// 上边界 { ための(自動TMP:VEの[J]) { 更新(1、1 、xsz、tmp.first、tmp.second)。 } ANS = MAX(ANS、TR [ 1 ] .MX)。 } } のprintf(" %LLDを\ n " 、ANS)。 } }