一篇题解
# 窗口的星星
前置知识:扫描线
# 输入格式
本题有多组数据,第一行为 ,表示有 组数据。
对于每组数据:
第一行 个整数 表示有 颗星星,窗口宽为 ,高为 。
接下来 行,每行三个整数 表示星星的坐标在 ,亮度为 。
# 输出格式
个整数,表示每组数据中窗口星星亮度总和的最大值。
# 分析:
我们很快就会有一种很暴力的思路,那就是我们可以对于每一个星星,以它为边界构造那个窗口,然后遍历其他的星星是否在这里面,然后求一下权值,那么复杂度显然是 。显然是不能过的。那么我们就只能另辟奇径了。
我们先画个图。
我们会发现,如果是给定一个窗口,那么同窗口的星星所扩展出的矩形就一定会又交集,为图中的蓝色部分,因为我们的星星是可以向上扩展高为窗口宽的矩形,那么两个星星就构成的矩形一定会产生交集,那么我们现在再考虑,此时如果我们能够求出最大的矩形的组合体的面积,然后再求一下区间的最值不就是答案吗。这里需要感性的理解一下,因为我们可以在更新块的时候求出最大值。
那么求这个面积的方法是什么。那必然就是扫描线!!!
记得离散化因为这个坐标给的实在是太大了。
下面是代码实现
#include <iostream> | |
#include <algorithm> | |
#include <queue> | |
#include <cstring> | |
#define int long long | |
using namespace std; | |
inline int read() | |
{ | |
int x = 0, f = 1; | |
char ch = getchar(); | |
while(ch > '9' || ch < '0') | |
{ | |
if(ch == '-') | |
f = -1; | |
ch = getchar(); | |
} | |
while(ch >= '0' && ch <= '9') | |
x = x * 10 + ch - '0', ch = getchar(); | |
return x * f; | |
} | |
inline void write(int x) | |
{ | |
if(x < 0) | |
{ | |
x = -x; | |
putchar('-'); | |
} | |
if(x > 9) | |
write(x / 10); | |
putchar(x % 10 + '0'); | |
} | |
const int N = 2e5 + 10; | |
int t; | |
int n, h, w; | |
int val[N]; | |
struct Tree // 存放每个矩形的上底和下底 | |
{ | |
int l, r, h, val; | |
bool operator < (const Tree& a) | |
{ | |
if(h != a.h) | |
return h < a.h; | |
return val > a.val; | |
} | |
} Tr[N << 2]; | |
struct SegmentTree // 扫描线 | |
{ | |
int l, r, mx, tag; | |
} tr[N << 2]; | |
void ms() | |
{ | |
memset(tr, 0, sizeof (tr)); | |
memset(Tr, 0, sizeof (Tr)); | |
} | |
void pushup(int u) | |
{ | |
tr[u].mx = max(tr[u << 1].mx, tr[u << 1 | 1].mx); | |
} | |
void build(int u, int l, int r) | |
{ | |
tr[u].l = l, tr[u].r = r, tr[u].mx = tr[u].tag = 0; | |
if(l == r) | |
return; | |
int mid = (l + r) >> 1; | |
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r); | |
} | |
void pushdown(int u) | |
{ | |
tr[u << 1].mx += tr[u].tag; | |
tr[u << 1 | 1].mx += tr[u].tag; | |
tr[u << 1].tag += tr[u].tag; | |
tr[u << 1 | 1].tag += tr[u].tag; | |
tr[u].tag = 0; | |
} | |
void modify(int u, int L, int R, int k) | |
{ | |
int l = tr[u].l, r = tr[u].r; | |
if(L <= l && R >= r) | |
{ | |
tr[u].mx += k; | |
tr[u].tag += k; | |
return ; | |
} | |
pushdown(u); | |
int mid = (l + r) >> 1; | |
if(L <= mid) | |
modify(u << 1, L, R, k); | |
if(R > mid) | |
modify(u << 1 | 1, L, R, k); | |
pushup(u); | |
} | |
signed main() | |
{ | |
t = read(); | |
while(t -- ) | |
{ | |
ms(); | |
n = read(), w = read(), h = read(); | |
for(register int i = 1 ; i <= n ; i ++ ) | |
{ | |
int x, y, l; | |
x = read(), y = read(), l = read(); | |
val[(i << 1) - 1] = y; | |
val[i << 1] = y + h - 1; | |
Tr[(i << 1) - 1] = (Tree){y, y + h - 1, x , l}; // 下底 | |
Tr[i << 1] = (Tree){y, y + h - 1, x + w - 1, -l}; // 上底 | |
} | |
n <<= 1; | |
sort(val + 1, val + n + 1); | |
sort(Tr + 1, Tr + n + 1); | |
int cnt = unique(val + 1, val + n + 1) - val - 1; | |
for(register int i = 1 ; i <= n ; i ++ ) // 离散化 | |
{ | |
int p1 = lower_bound(val + 1, val + cnt + 1, Tr[i].l) - val; | |
int p2 = lower_bound(val + 1, val + cnt + 1, Tr[i].r) - val; | |
Tr[i].l = p1; // 记录 l 和 r 的排名 | |
Tr[i].r = p2; | |
} | |
build(1, 1, cnt); | |
int ans = 0; | |
for(register int i = 1 ; i <= n ; i ++ ) | |
{ | |
modify(1, Tr[i].l, Tr[i].r, Tr[i].val); | |
ans = max(ans, tr[1].mx); | |
} | |
write(ans); | |
puts(""); | |
} | |
return 0; | |
} |
★,°:.☆( ̄▽ ̄)/$:.°★ 。完结