题解/算法 {2736. 最大和查询}
LINK: https://leetcode.cn/problems/maximum-sum-queries/
;
从几何的角度去思考 (否则这个题很难有思路), 即平面的第一象限上有两类点: {A类, B类}, 对于每个B类点 求他的右上角 (即 ≥ x , ≥ y \geq x, \geq y ≥x,≥y)区域的所有A类点中 x + y x+y x+y的最大值;
将{A,B类}点 都放到一起(一个序列里面) 然后排序(先对X排序, 后对Y排序) (对于重合点 要保证B类 < A类
), 此时 对于任意的B类点curB
所有满足要求的A类点 都是在这个点的后面; 换句话说, curB
这个点的后面所有A类点中 满足Y坐标
≥
c
u
r
Y
\geq curY
≥curY的, 就是所有满足要求的A类点;
即, curB
后面所有的A类点, 按照其Y坐标 分成了2类:
≥
c
u
r
Y
\geq curY
≥curY和
<
c
u
r
Y
< curY
<curY的, 我们要求
≥
c
u
r
Y
\geq curY
≥curY里的所有点 的最大值;
.
此时其实就已经线性化了, 即问题转换为: 一个区间 求一个子区间的最大值 (可以用线段树);
因为Y坐标很大, 进行哈希操作 则所有Y坐标是[0, 2e5]
的范围;
vector<int> maximumSumQueries( vector<int>& A, vector<int>& B, vector<vector<int>>& Q){
{ static bool __is_first = true; if( __is_first){ __is_first = false; __Initialize();} }
Hash_y->Initialize();
for( auto i : B) Hash_y->Add( i);
for( auto & i : Q) Hash_y->Add( i[ 1]);
Hash_y->Discretize();
using Item_ = tuple< int, int, int>;
vector< Item_> vec; vec.reserve( A.size() + Q.size());
//>> A类点 (后面的`123`是要保证: 重复点中 A类点要在B类点的后面);
for( int i = 0; i < (int)A.size(); ++i){
vec.emplace_back( A[i], B[i], 123);
}
//>> B类点 (后面的`-ind`是要保证: 重复点中 A类点要在B类点的后面);
for( int ind = 0; ind < (int)Q.size(); ++ind){
vec.emplace_back( Q[ind][0], Q[ind][1], -ind);
}
sort( vec.begin(), vec.end());
Tree->Initialize( Hash_y->Array_size);
vector< int> ANS( Q.size());
for( auto it = vec.rbegin(); it != vec.rend(); ++it){
auto x = get<0>( *it), y = get<1>( *it), flag = get<2>( *it);
auto hash_y = Hash_y->Get_hash( y);
if( flag > 0){
Tree->Modify( hash_y, hash_y, x + y);
continue;
}
// 注意, B类点不能放到线段树里;
auto ret = Tree->Query( hash_y, Hash_y->Array_size - 1);
ANS[ -flag] = ret;
}
return ANS;
}