→传送窗口

(复制一下题面好了~)

题目背景

小卡买到了一套新房子,他十分的高兴,在房间里转来转去。

题目描述

晚上,小卡从阳台望出去,“哇~~~~好多星星啊”,但他还没给其他房间设一个窗户,天真的小卡总是希望能够在晚上能看到最多最亮的星星,但是窗子的大小是固定的,边也必须和地面平行。这时小卡使用了超能力(透视术)知道了墙后面每个星星的位置和亮度,但是小卡发动超能力后就很疲劳,只好拜托你告诉他最多能够有总和多亮的星星能出现在窗口上。

输入输出格式

输入格式:

本题有多组数据,第一行为T 表示有T组数据T<=10

对于每组数据

第一行3个整数n,W,H,(n<=10000,1<=W,H<=1000000)表示有n颗星星,窗口宽为W,高为H。

接下来n行,每行三个整数xi,yi,li 表示星星的坐标在(xi,yi),亮度为li。(0<=xi,yi<2^31)

输出格式:

T个整数,表示每组数据中窗口星星亮度总和的最大值。

输入输出样例

输入样例#1:

2
3 5 4
1 2 3
2 3 2
6 3 1
3 5 4
1 2 3
2 3 2
5 3 1
输出样例#1:

5
6

说明

小卡买的窗户框是金属做的,所以在边框上的不算在内。


喜欢这个题目背景~

这类题目有一个很巧妙的转化,把移动的窗口(面)和星星(点)转成 可以覆盖到星星的(面)和窗口的左下角(点)

什么意思呢?(可以结合下面的图片理解)

把每一个星星作为右上角,在它的左下方划出一片窗口大小的区域,表示只要窗口的左下角落在这一片区域里就一定能覆盖到这颗星星。

那么不同星星的重叠部分就代表能同时覆盖这几颗星星了。

(下图中,只要窗口落在阴影部分,就能同时覆盖到三颗星星)

所以这一题的解法就是:

想象一条扫描线从左扫到右边,只要进入了星星的区域,扫描线上这段区间就可以取到这颗星星的值,等过了区域再减去这颗星星的值。

那就可以用线段树来做啦,每次挪动找出区间的最值更新答案就可以了。

看到题目最后的提示:小卡买的窗户框是金属做的,所以在边框上的不算在内。(惊!

边框居然不算,好吧那就只好把范围缩小,到了阴影部分外的那条平行y轴的线就可以把这颗星星的贡献减掉了。(用Windows XP 画的的图,有点丑)

还有,星星的坐标很大,记得离散化。

具体操作细节可以看代码(用了vector来维护坐标上加和减的星星)

(代码虽然很长,但结构还算清晰吧)

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<algorithm> #define For(i,a,b) for(int i=a;i<=b;++i)
#define Pn putchar('\n')
#define llg long long using namespace std; const int N=2e4+; struct LIS{
int x,y,id;
}Lis[N*]; struct Star{
int x1,x2,y1,y2;
llg lgt;
Star(){
x1=; x2=; y1=; y2=;
lgt=;
}
}st[N]; vector<int>ads[N];
vector<int>mns[N]; int tot=,n,m,W,H,x,y;
llg tag[N*],mx[N*],ans=; void read(int &v){ //读入优化,和输出优化
v=; bool fg=;
char c=getchar(); if(c=='-')fg=;
while(c<''||c>''){c=getchar(); if(c=='-')fg=;}
while(c>=''&&c<=''){v=v*+c-'',c=getchar();if(c=='-')fg=;}
if(fg)v=-v;
}
void read(llg &v){
v=; bool fg=;
char c=getchar(); if(c=='-')fg=;
while(c<''||c>''){c=getchar(); if(c=='-')fg=;}
while(c>=''&&c<=''){v=v*+c-'',c=getchar();if(c=='-')fg=;}
if(fg)v=-v;
}
void write(int x){
if(x>)write(x/);
int xx=x%;
putchar(xx+'');
}
//排序
bool cmpX(const LIS &a,const LIS &b){
return a.x<b.x;
}
bool cmpY(const LIS &a,const LIS &b){
return a.y<b.y;
}
//线段树操作
void pDown(int o){
llg tg=tag[o]; tag[o]=;
int ls=o<<,rs=o<<|;
tag[ls]+=tg; tag[rs]+=tg;
mx[ls]+=tg; mx[rs]+=tg;
}
void Ins(int o,int l,int r,int lx,int rx,llg dt){
if(lx<=l&&rx>=r){
mx[o]+=dt; tag[o]+=dt;
return;
}
int m=(l+r)>>;
int ls=o<<,rs=o<<|;
if(tag[o])pDown(o);
if(lx<=m)Ins(ls,l,m,lx,rx,dt);
if(rx>m)Ins(rs,m+,r,lx,rx,dt);
mx[o]=max(mx[ls],mx[rs]);
} int main(){
int T; read(T);
while(T--){
tot=; ans=;
memset(tag,,sizeof(tag));
memset(mx,,sizeof(mx)); read(n); read(W); read(H);
For(i,,n){ //存下星星区域的右上角和左下角
read(x); read(y); read(st[i].lgt);
st[i].x1=st[i].x2=st[i].y1=st[i].y2=;
Lis[++tot].x=x;
Lis[tot].y=y,Lis[tot].id=i; Lis[++tot].x=x+W-;
Lis[tot].y=y-H+,Lis[tot].id=i;
}
Lis[].x=-;
Lis[].y=-; sort(Lis+,Lis+tot+,cmpY); //分别对X和Y离散化
int ty=;
For(i,,tot){
if(Lis[i].y!=Lis[i-].y)ty++;
int ID=Lis[i].id;
if(!st[ID].y2){
st[ID].y2=ty;
}else{
st[ID].y1=ty;
}
} sort(Lis+,Lis+tot+,cmpX);
int tx=;
For(i,,tot){
if(Lis[i].x!=Lis[i-].x)tx++;
int ID=Lis[i].id;
if(!st[ID].x1){
st[ID].x1=tx;
}else{
st[ID].x2=tx;
}
} For(i,,tx+){ //初始化vector
ads[i].clear();
mns[i].clear();
} For(i,,n){
int lx,rx; //把星星挂到相应的横坐标上
lx=st[i].x1; //ads为加, mns为减
rx=st[i].x2+;
ads[lx].push_back(i);
mns[rx].push_back(i);
}
For(i,,tx){
int sz; sz=mns[i].size();
For(j,,sz-){ //先减后加
int ID=mns[i][j];
int lx,rx;
lx=st[ID].y2;
rx=st[ID].y1;
Ins(,,ty,lx,rx,-st[ID].lgt); } sz=ads[i].size();
For(j,,sz-){
int ID=ads[i][j];
int lx,rx;
lx=st[ID].y2;
rx=st[ID].y1;
Ins(,,ty,lx,rx,st[ID].lgt);
}
ans=max(ans,mx[]);
}
write(ans); Pn;
}
return ;
}

最新文章

  1. C++算法实源码分析
  2. GPU keylogger &amp;&amp; GPU Based rootkit(Jellyfish rootkit)
  3. 利用IronJs在.NET程序里面跑javascript脚本
  4. mac 下安装nginx
  5. xStream完美转换XML、JSON_java
  6. Poj 2777 Count Color(线段树基础)
  7. Redis源代码分析(23)--- CRC循环冗余算法RAND随机数的算法
  8. python socket编程---从使用Python开发一个Socket示例说到开发者的思维和习惯问题
  9. READ TABLE 的用法
  10. SQL性能优化应该考虑哪些?
  11. HTML5 全屏 API
  12. android Timer与TimerTask的相关操作
  13. elasticSearch安装 Kibana安装 Sense安装
  14. 网络流(四)dinic算法
  15. BZOJ1419Red is good——概率DP
  16. Flume 案例 Telnet安装及采集Telnet发送信息到控制台
  17. 关于Tomcat配置虚拟路径保存、访问图片
  18. Beginning SDL 2.0(5) 基于MFC和SDL的YuvPlayer
  19. 硬件RDMA的驱动配置和测试
  20. Monkey学习笔记&lt;三&gt;:Monkey脚本编写

热门文章

  1. ubuntu 查看网卡 数据包处理 速度
  2. NSArray / NSSet / NSDictory 三者的异同点
  3. MongoDB 倾向于将数据都放在一个 Collection 下吗?
  4. Codeforces Beta Round #88 C. Cycle —— DFS(找环)
  5. 近期测试BUG总结
  6. ffmpeg: error while loading shared libraries: libavdevice.so.52
  7. 谈谈嵌套for循环的理解
  8. 动态链接库的ELF头分析
  9. BeginPaint/EndPaint(CPaintDC)与GetDC(CClientDC)的区别
  10. Java笔记(五)