借鉴了其他小伙伴的思路。
先来考虑─种较为暴力的做法。
根据给定的军功值,建一个二维前缀和数组。
那么,遍历所有可能的轰炸窗口的军功和,最大值就是解。但在本题中,该方法有两方面的限制:
由于心,y ≤231 _1,没法直接建立前缀和数组(存不下)。
可能你想到了离散化,但即便离散化也不行,因为遍历需要的时间复杂度:O(Tni2'),且常数不小,可能会TLE;空间复杂度:O(n2),限制内存为128M,可能会MLE。
接下来考虑如何优化。
首先,当然要对所有坐标进行离散化。
注意到轰炸窗口的长L、宽W都是固定的,因此不必遍历、存储整个地图,只需维护一部分信息即可,这里采用线段树扫描线+双指针来处理。
做法:
先对坐标从小到大排序,i为其第i个元素;
初始化右指针r — 1 ;
遍历左指针l<— 1 : n,将右指针r右移k 次,即r <---T+k,使得[xl , xr]恰好不超过轰炸窗口的范围( k可能为0 ) ;
每次r指针右移,用所有在直线α = 上的点,将该点纵坐标g的对应区间加上其军功值(进入扫描线);
每次l指针右移,进行类似于右指针r的操作,减去其军功值(退出扫描线);
对于点(x0, y0),其更新的区间为[y0,y0 +W) ;
因此, y坐标对区间端点离散化即可。
每次指针移动完成后,用所有区间中的最大值更新答案。因此,使用线段树即可满足上述区间修改、维护最值的要求。
时间复杂度分析:排序、离散化、建树均为O(n log n),每个点最多更新2次,区间更新O(log n),故为O(Tn log n)
Code :
1.#include
2.#include
3.using namespace std;
4.
5. const int maxn = 2e4 + 7,maxs = maxn *2;
6.
7. int N;
8.long long sg[maxs *4],lz[maxs *4];
9.
10.#define lc (u<<1)
11.#define rc (lc | 1)
12.void build(int u = 1, int l = 0, int r = N) {
13.sg[u] = lz[u] = 0LL;
14.if (l < r - 1) {
15.int mid = (l +r) / 2;
16.build(lc, l, mid);
17.build(rc, mid,r);
18.}
19.} // build
20. void down( int u,long long v) {
21.sg[u] += V;22.lz[u] += v;23.}
24. void pushdown( int u) {
25.if (lz[u]){
26. down( lc,lz[u]);
27. down(rc,lz[u]);
28. lz[u] = o;
29.}
30.}
31.void pushup(int u) {
32.sg[u] = max( sg[lc], sg[rc]);
33.}
34.int yp[ maxs];
35.void add(int ll, int rr, int v, int u = 1, int li = o, int ri = N) {
36.int L = yp[li],R = yp[ri];
37.if (ll <= L && R <= rr) {
38.
down(u,v);
39.
}else if (li < ri - 1){
40.
pushdown(u);
41.
int mi = (li + ri) / 2;
42.
int M = yp[mi];
43.
if (ll <M) add(ll,rr,v,lc,li, mi);
44.
if (M<rr) add(ll,rr,v, rc,mi, ri);
45.
pushup(u);
46.}
47.}
48.
49. int xx[ maxn],yy[maxn],wv[ maxn], idx[ maxn],yl[maxn],yr[maxn];
50.
51.long long solve(int n, int L, int W) {
52.yp[o] = o, yp[1] = ~0U >> 1;//边界
53. N= 2;//离散点总个数
54.
for (int i = 0; i < n; ++i) {
55.
idx[i] = i;
56.
int l = yy[i],r = yy[i] + w;
57.
//越界处理
58.
if (l < 0) l = 0;
59.
if (r <0) r = ~OU >>1;
60.
yl[i] = l, yr[i] = r;
61.
yp[N++] = l,yp[N++] = r; //区间端点离散化
62.
}
63.
sort(yp, yp + N);
64.
N= unique(yp,yp + N) - yp - 1;//去重
65.
build( ) ;
66.
sort(idx,idx + n,[&](int a,int b) {
67.
return xx[ a] < xx[ b];
68.
}};
69.
70.
auto update = [&](int j, int a) {
71.
int id = idx[j],l = yl[id], r = yr[id];
72.
add(l,r, a * ww[ id]);
73.
};
74.
long long ans = 0LL;
75.
int 1 = o,r = 0;
76.
while (r <n){
77.
while (xx[idx[r]] - xx[idx[l]] >= L) update(l,-1);++l;
78.
while (r < n && xx[idx[r]] - xx[idx[l]]<L) update(r,+1);++r;
79.
ans = max( ans, sg[1]);
80.
}
81.return ans;
82.} //solve
83.
84.int main() {
85.cin.tie(o) -> sync_with_stdio(false);
86.int t;
87.
cin >> t;
88.
while (t--) {
89.
int n,L, w;
90.
cin >> n >>L >> W;
91.
for (int i = 0; i < n; ++i) {
92.
cin >> xx[i] >> yy[i] >> ww[i];
93.
// x,y范围是[1,INT_MAX],这里采用了"左闭右开"原则,右边界+1会爆INT_MAX
94.
/因此将x,y均减一,从而保证各端点始终在int的范围[0,INT_MAX]之内
95.
--xx[i],--yy[i];
96.
}
97.
cout << solve(n,L, W)<<"\n";
98.
}
99.
return o;
100.}