Stars in the window [segment tree + scan line + discretization + lazy mark]
POJ2482
、ACwing248
topic:
There are many stars in a sky (think of a plane rectangular coordinate system), and the coordinates and brightness of each star are known (both integers).
Find the maximum total brightness of the stars that can be encircled by a rectangular window of width W and height H (W and H are positive integers). (stars on rectangle borders don't count)
Input format:
The input contains sets of test cases.
The first line of each use case contains 3 integers: n, W, H, representing the number of stars, and the width and height of the rectangular window.
Then there are n lines, each with 33 integers: x, y, c, representing the position (x, y) and brightness of each star.
No two stars are at the same point.
Output format:
Each test case outputs a maximum sum of luminance.
One line for each result.
data range:
1≤n≤10000,
1≤W,H≤1000000,
0≤x,y<231
Input sample:
3 5 4
1 2 3
2 3 2
6 3 1
3 5 4
1 2 3
2 3 2
5 3 1
Sample output:
5
6
Code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e4+5;
int n,W,H,k;
//----------------------------------------
vector<int> v; //用于y轴离散化
int find_w(int x){
//找到离散化后代表x的数字
return lower_bound(v.begin(),v.end(),x) - v.begin();
}
//----------------------------------------
struct Edge{
int x,y1,y2,c; //分别表示星星的坐标和亮度
} e[N << 2]; //存储四元组
bool cmp(Edge a,Edge b){
if(a.x == b.x)
return a.c < 0;
return a.x < b.x;
} //按照x排序,方便从左到右扫描
//----------------------------------------
struct T{
int l,r; //区间
int ans,lazy; //答案、lazy标记
} tree[N << 3]; //存储线段树
void build(int p,int l,int r){
//建立线段树
tree[p] = {
l,r,0,0};
if(l == r)
return;
int lc = p<<1,rc = p<<1|1,mid = l+r>>1;
build(lc,l,mid);
build(rc,mid + 1,r);
}
void push_down(int p){
//消除lazy标记
int lc = p<<1,rc = p<<1|1,lazy = tree[p].lazy;
tree[lc].ans += lazy;
tree[lc].lazy += lazy;
tree[rc].ans += lazy;
tree[rc].lazy += lazy;
tree[p].lazy = 0;
}
void update(int p,int l,int r,int c){
//如果全覆盖的话,可以不着急更新子结点,使用lazy标记做记录
if(tree[p].l == l && tree[p].r == r){
tree[p].lazy += c;
tree[p].ans += c;
return;
}
push_down(p); //如果没有全覆盖,则应该线更新子节点后再访问子节点
int lc = p<<1,rc = p<<1|1,mid = tree[p].l+tree[p].r>>1;
if(r <= mid)
update(lc,l,r,c);
else if(l > mid)
update(rc,l,r,c);
else
update(lc,l,mid,c),update(rc,mid + 1,r,c);
tree[p].ans = max(tree[lc].ans,tree[rc].ans); //更新该结点
}
signed main(){
int x,y,c;
while(cin>>n>>W>>H){
k = 0;
v.clear();
for(int i = 0;i < n;++i){
cin>>x>>y>>c;
e[++k] = {
x,y,y + H - 1,c};
e[++k] = {
x + W,y,y + H - 1,-c};
v.push_back(y),v.push_back(y + H - 1);
}
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end()); //去重离散化
sort(e + 1,e + k + 1,cmp); //排序,以便后续扫描
build(1,0,v.size() - 1); //建立线段树
int ans = 0;
for(int i = 1;i <= k;++i){
//扫描到这条边的时候根据c的值考虑是要加入这个星星的亮度还是减去这个星星的亮度
update(1,find_w(e[i].y1),find_w(e[i].y2),e[i].c);
//更新ans
ans =max(ans,tree[1].ans);
}
cout<<ans<<"\n";
}
return 0;
}