以下内容来自ShallWe‘s blog
题目
2014 UESTC Training for Data Structures D - 长使英雄泪满襟
看出司马懿在等蜀军粮草不济,孔明于是下令分兵屯田以备久战。司马懿日日只是闭营不出。孔明每日思虑对策至天明,却也无可奈何。漫天星辰中有一类星叫做将星,它们随着将魂的燃烧会越发明亮。今夜五丈原的星空格外璀璨。司马懿一声轻叹。五丈原的星,要落了。
Input
第一行输入三个整数\(n\),\(W\),\(H\),分别表示有\(n\)颗星,矩形宽\(W\),高\(H\)。
接下来\(n\)行,每行三个整数,\(x_i\),\(y_i\),\(w_i\)。表示第\(i\)颗星星的在天空的位置是\((x_i,y_i)\),亮度是\(w_i\)。
1≤n≤100000,1≤W,H≤1000000,0≤x,y≤100000000,1≤wi≤100
Output
仅一行,该行只包含一个整数,表示平移矩形后,矩形内星星的亮度之和最大能是多少。
解题报告
比较简单的一道扫描线+线段树维护信息的题目。
说说怎么想的,首先,由于矩形的长\(w\),宽\(h\)都是已知的,所以只要固定右下点(当然也可以是别的)那矩形可以控制的stars就是确定的。
比较容易想到的是分别考虑\(x\),\(y\),首先解决\(y\),可以使用扫描线,形象些就是从左向右移动矩形的左边,这样,对于按照\(y\)排序的星星,\(O(n)\)就可以确定哪些在矩形的左右范围内(对于当前左边)。
此时再来处理\(x\),考虑每个星星可以为哪些位置的右下点提供价值,很显然就是一个连续的区间\([x,x+len-1]\)其中,\(len\bf\)是离散化后预处理出来的。所以,当一个星星加入矩形,就是要添加一条线段,使用线段树区间修改全局max来支持操作。
代码
#include <iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstdlib>
using namespace std;
const int N=10001;
struct node{
int l,r,mark,mx;
} seg[N<<2];
int n,W,H;
struct Star{
int x,y,w,len;
bool real;
} star[N<<1];
bool cmpy(const Star &a,const Star &b){
return a.y==b.y?a.x<b.x:a.y<b.y;
}
bool cmpx(const Star &a,const Star &b){
return a.x==b.x?a.y<b.y:a.x<b.x;
}
void build(int x,int l,int r){
seg[x].l=l;seg[x].r=r;
if (l==r){
seg[x].mx=seg[x].mark=0;
return;
}
int mid=(l+r)>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
}
void push_down(int x){
if (seg[x].mark!=0){
seg[x*2].mark+=seg[x].mark;
seg[x*2+1].mark+=seg[x].mark;
seg[x*2].mx+=seg[x].mark;
seg[x*2+1].mx+=seg[x].mark;
seg[x].mark=0;
}
return;
}
void add(int l,int r,int x,int val){
bool b=false;
if (seg[x].l==seg[x].r){
seg[x].mx+=val;
return;
}
if (seg[x].l==l&&seg[x].r==r){
seg[x].mark+=val;
seg[x].mx+=val;
return;
}
push_down(x);
int mid=(seg[x].l+seg[x].r)>>1;
if (l>mid){
add(l,r,x<<1|1,val);b=true;
}
if (r<=mid){
add(l,r,x<<1,val);b=true;
}
if (!b) {
add(l,mid,x*2,val);
add(mid+1,r,x*2+1,val);
}
seg[x].mx=max(seg[x<<1].mx,seg[x<<1|1].mx);
}
int main(){
freopen("stars.in","r",stdin);
freopen("stars.out","w",stdout);
int g,h,j,l;
while(cin>>n>>W>>H){
memset(seg,0,sizeof(seg));
memset(star,0,sizeof(star));
for (j=0;j<n;j++)
scanf("%d%d%d",&star[j].x,&star[j].y,&star[j].w);
sort(star,star+n,cmpy);
h=1;g=0;
while (g<n){
while (g<n && star[g].y==star[g+1].y){
star[g].len=h;
g++;
}
star[g].len=h;
h++;g++;
}
g=0;
for (j=0;j<n;j++){
while (g<n&&star[j].y+H>star[g].y) g++;
g--;
star[j].y=star[j].len;
star[j].len=star[g].len-star[j].len+1;
}
h=star[n-1].y;
for (j=0;j<n;j++){
star[j].real=true;
star[j+n].x=star[j].x-W;
star[j+n].y=star[j].y;
star[j+n].w=star[j].w;
star[j+n].real=false;
star[j+n].len=star[j].len;
}
sort(star,star+2*n,cmpx);
build(1,1,h);
int max=-1;
for (j=0;j<2*n;j++){
if (star[j].real) l=-1;else l=1;
add(star[j].y,star[j].y+star[j].len-1,1,l*star[j].w);
if (seg[1].mx>max) max=seg[1].mx;
}
cout<<max<<endl;
}
return 0;
}