hdu-6638 线段树 最大子段和

hdu-6638 线段树 最大子段和

题意

给你n个坐标,每个坐标有权值(可正可负),目标是找一个平行于坐标轴矩阵,使得矩阵内的取值求和最大,输出最大值。这个矩阵的坐标可以是非整数的,但是输入是整数的,暗示单个点也是可以被框出来的。

思路

比较容易想到的是,先离散化坐标,求一个最大子矩阵好像就可以了。

img1

但是想想这个复杂度,对于一个二维数组求最大子矩阵的话,复杂度是$O(n^3)$的,这里2000个点可以对角线排列,那么二维数组的大小就是2000x2000的,三次的复杂度其实不可接受。

img2

然后就去想,这个题里的点其实比较稀疏,只占二维平面里的一点点空间,而一般的做法第三维是需要一次$O(n)$的遍历来做区间最大子段和的,那么在这个问题里我们可以想办法在更少的时间算出最大子段和,并且避开遍历n次的时间。

做法就是用线段树来维护最大子段和,对于那些落在边界内部的点,可以预处理排序所有的点,这样可尺取地逐步放入边界里的点,放完了就可以用线段树得到当前的答案,然后继续移动边界,把下面的点加入线段树,继续计算答案并更新。

这个线段树的设计可以是单点更新$O(log(n))$,并$O(1)$询问的。总体复杂度$O(n^2log(n))$

数组说明
1
2
3
4
ll sum[TreeSize]; //表示区间和
ll lft[TreeSize]; //表示当前区间左边开始连续的最大子段和
ll rht[TreeSize]; //表示当前区间右边开始连续的最大子段和
ll ans[TreeSize]; //表示当前区间的答案(最大字段和)
Pro.ID Exe.Time Exe.Memory Language Author
6638 2308MS 1760K G++ tieway59
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#include <bits/stdc++.h>

#define _debug(x) cerr<< #x << " = "<<x <<endl

using namespace std;
typedef long long ll;
const ll INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int MAXN = 4000 + 59;
const int TreeSize = MAXN << 2;


struct SegTree {

#define lson (oo<<1)
#define rson (oo<<1|1)

int n;
ll sum[TreeSize];
ll lft[TreeSize];
ll rht[TreeSize];
ll ans[TreeSize];

void init(int _n) {
this->n = _n;
build(1, 1, _n);
}

void build(int oo, int l, int r) {
if (l == r) {
sum[oo] = lft[oo] = rht[oo] = ans[oo] = 0;
return;
}
int m = (l + r) >> 1;
build(lson, l, m);
build(rson, m + 1, r);
sum[oo] = lft[oo] = rht[oo] = ans[oo] = 0;
}

void update(int oo, int l, int r, int pos, ll val) {
if (l == r && r == pos) {
sum[oo] += val;//+val?
rht[oo] = max(0ll, sum[oo]);
lft[oo] = max(0ll, sum[oo]);
ans[oo] = max(0ll, sum[oo]);
return;
}

int m = (l + r) >> 1;
if (pos <= m)
update(lson, l, m, pos, val);
else
update(rson, m + 1, r, pos, val);

lft[oo] = lft[lson];
rht[oo] = rht[rson];

sum[oo] = sum[lson] + sum[rson];
ans[oo] = max(ans[lson], ans[rson]);
ans[oo] = max(ans[oo], rht[lson] + lft[rson]);

lft[oo] = max(lft[oo], sum[lson] + lft[rson]);
rht[oo] = max(rht[oo], rht[lson] + sum[rson]);

if (lft[lson] == sum[lson])
ans[oo] = max(ans[oo], lft[lson] + lft[rson]);

if (rht[rson] == sum[rson])
ans[oo] = max(ans[oo], rht[lson] + rht[rson]);
}

void update(int pos, ll val) {
update(1, 1, n, pos, val);
}

ll query() {
return ans[1];
}
};

SegTree tree;

struct point {
int x, y, v;
} p[MAXN];


int dsc[MAXN], dtot;

void initDsc() {
sort(dsc, dsc + dtot);
dtot = unique(dsc, dsc + dtot) - dsc;
}

int getDsc(const int &val) {
return lower_bound(dsc, dsc + dtot, val) - dsc + 1;
}


int n;
ll ans;
int Kase;
int xmax, ymax;

int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);

cin >> Kase;
while (Kase--) {
ans = 0;
dtot = 0;
xmax = ymax = 0;

cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> p[i].x >> p[i].y >> p[i].v;
dsc[dtot++] = p[i].x;
dsc[dtot++] = p[i].y;
}
initDsc();

for (int i = 1; i <= n; ++i) {
p[i].x = getDsc(p[i].x);
p[i].y = getDsc(p[i].y);
xmax = max(xmax, p[i].x);
ymax = max(ymax, p[i].y);
}

sort(p + 1, p + 1 + n, [](const point &a, const point &b) {
if (a.x == b.x)return a.y < b.y;
return a.x < b.x;
});

for (int l = 1; l <= n; l++) {
tree.init(ymax);
for (int r = l; r <= n; r++) {
tree.update(p[r].y, p[r].v);
if (p[r].x != p[r + 1].x) {
ans = max(ans, tree.query());
}
}
while (p[l].x == p[l + 1].x)l++;
}

cout << ans << '\n';
}
return 0;
}
/*
2
4
1 1 50
2 1 50
1 2 50
2 2 -500
2
-1 1 5
-1 1 1

*/
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×