Description
长长的情书题面自动省略之……
Here comes the problem: Assume the sky is a flat plane. All the stars lie on it with a location (x, y). for each star, there is a grade ranging from 1 to 100, representing its brightness, where 100 is the brightest and 1 is the weakest. The window is a rectangle whose edges are parallel to the x-axis or y-axis. Your task is to tell where I should put the window in order to maximize the sum of the brightness of the stars within the window. Note, the stars which are right on the edge of the window does not count. The window can be translated but rotation is not allowed.
Input
There are several test cases in the input. The first line of each case contains 3 integers: n, W, H, indicating the number of stars, the horizontal length and the vertical height of the rectangle-shaped window. Then n lines follow, with 3 integers each: x, y, c, telling the location (x, y) and the brightness of each star. No two stars are on the same point.
There are at least 1 and at most 10000 stars in the sky.
1<=W,H<=1000000,0<=x,y<231.
Output
For each test case, output the maximum brightness in a single line.
Sample Input
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
I think
题意:给出若干星星的坐标及亮度和一个四边均平行于坐标轴的矩形长与宽,求该矩形框内星星的最大亮度(不包括矩形边框上的星星)。
算法:线段树+扫描线+离散化
思路:这道题的关键在于想到把星星转化为矩形。
一颗星星(x,y),它的亮度能够被圈进的位置范围是以(x,y),(x+w,y+h)两点连线为对角线的矩形(称该矩形为星星的矩形)。两星星的矩形相交就代表它们能被框进同一个矩形。则问题转化为求平面上矩形范围内的最大权值。
实现:对于每一颗星星,把它以两条带权边的形式存储(x,y,y+h,c)和(x+w,y,y+h,-c),两边权互为相反数,能够保证星星的亮度被限制在自己的矩形内。用线段树存储离散化后y轴坐标区间内权值的最大值mx。使扫描线在x轴方向上移动。遇到一条边,就在线段树上更新权值最大值,不同于矩形面积交之类,线段树上的标记需要下传,每次更新后用整个区间最大值更新ans。
由于矩形边框上的星星不能算入,在对星星存储的边排序时,要将负权边排在正权边的前面,这样就能保证先删边。
其实题目最终就转化成为线段树区间更新求最大值的模板题了。
Code
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int sm = 10000*2+50;
typedef long long lld;
lld w,h,n,T,t,z1;
lld x1,y1,ans;
lld y[sm<<2],mx[sm<<2];
lld mk[sm<<2],add[sm<<2];
struct line {
lld x,y1,y2,c;
}a[sm];//矩形左右边
lld Max(lld a,lld b) { return a>b?a:b; }
char ch;int f;
void read(lld &x) {
x=0,f=1;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();
x*=f;
}
bool cmp (line u,line v) {
if(u.x!=v.x) return u.x<v.x;
return u.c<v.c;//把负权边排在正权边的前面
}
void build(int k,int l,int r) {
if(l+1==r) {
mx[k]=mk[k]=add[k]=0;
return ;
}
int m=(l+r)>>1;
build(k<<1,l,m);
build(k<<1|1,m,r);
mx[k]=mk[k]=add[k]=0;
}
void pushdown(int k,int l,int r) {
int m=(l+r)>>1,ls=k<<1,rs=k<<1|1;
mk[ls]=mk[rs]=1;
add[ls]+=add[k],add[rs]+=add[k];//是+add[k]而不是add[ls]
mx[ls]+=add[k],mx[rs]+=add[k];
add[k]=0,mk[k]=0;
}
void update(int k,int l,int r,line x) {
if(x.y1<=y[l]&&y[r]<=x.y2) {
mk[k]=1,add[k]+=x.c;
mx[k]+=x.c;return;
}
if(l+1==r)return;
if(mk[k])pushdown(k,l,r);
int m=(l+r)>>1,ls=k<<1,rs=k<<1|1;
if(x.y1<y[m]) update(ls,l,m,x);
if(x.y2>y[m]) update(rs,m,r,x);
mx[k]=Max(mx[ls],mx[rs]);
}
int main() {
while(scanf("%lld%lld%lld",&n,&w,&h)!=EOF) {
ans=t=0;
for(int i=1;i<=n;++i) {
read(x1),read(y1),read(z1);
y[++t]=y1,a[t].x=x1;
a[t].y1=y1,a[t].y2=y1+h,a[t].c=z1;
y[++t]=y1+h,a[t].x=x1+w;
a[t].y1=y1,a[t].y2=y1+h,a[t].c=-z1;
}
sort(y+1,y+t+1);
T=unique(y+1,y+t+1)-y-1;//去重
build(1,1,T);
sort(a+1,a+t+1,cmp);
for(int i=1;i<=t;++i) {
update(1,1,T,a[i]);
ans=Max(ans,mx[1]);
}
printf("%lld\n",ans);
}
return 0;
}