→传送窗口

(复制一下题面好了~)

题目背景

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

题目描述

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

输入输出格式

输入格式:

本题有多组数据,第一行为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 ;
}

【Luogu P1502】 窗口的星星的更多相关文章

  1. luogu P1502 窗口的星星

    题目链接 P1502 窗口的星星 题解 扫描线+线段树 线段树的每一个节点处理的是左边框放在当前x-1位置时的框内星星的亮度大小 按照x坐标进行离散化,得到离散化后每一个坐标x的可影响的范围 维护扫描 ...

  2. 洛谷 P1502 窗口的星星 解题报告

    P1502 窗口的星星 题目背景 小卡买到了一套新房子,他十分的高兴,在房间里转来转去. 题目描述 晚上,小卡从阳台望出去,"哇~~~~好多星星啊",但他还没给其他房间设一个窗户, ...

  3. 洛谷p1502窗口的星星 扫描线

    题目链接:https://www.luogu.org/problem/P1502 扫描线的板子题,把每个点看成矩形,存下边(x,y,y+h-1,li)和(x+w-1,y,y+h-1),在按横坐标扫线段 ...

  4. 【Luogu P1502】窗口的星星

    Luogu P1502 题意很好理解,就是问给出的矩形套住的最大和. 但是做起来却十分麻烦. --来自疯狂爆10分的愤怒 一个比较高效的思路是--把每一个星星作为左下角向右上方拓展形成一个矩形, 拓展 ...

  5. 【洛谷 P1502】 窗口的星星(扫描线)

    题目链接 把每个星星作为左下角,做出长为\(w-0.5\),宽为\(h-0.5\)的矩形. \(-0.5\)是因为边框上的不算. 离散化\(y\)坐标. 记录\(2n\)个\(4\)元组\((x,y1 ...

  6. 【louguP1502】窗口的星星

    题目链接 用两条扫描线从左往右扫描,距离为W,右边的扫描线扫到就加上,左边的扫到就减去, 线段树上的一点\(x\)维护\((x,x+H)\)的星星总价值,修改时直接修改\((x-H,x)\)就行了 坐 ...

  7. luogu1502 窗口的星星

    扫描线应该打懒标记的-- #include <algorithm> #include <iostream> #include <cstdio> using name ...

  8. Luogu1502 窗口的星星 (线段树扫描线)

    将每个点拓展为矩形,将\(y\)离散,延\(x\)轴扫描,每次更新最值 用了一百年的pushdown操作疑似有问题,亦或这道题特殊,我乱改了pushdown位置就过了,我能怎么办,WA了一发,y数组没 ...

  9. 【学习笔记】线段树—扫描线补充 (IC_QQQ)

    [学习笔记]线段树-扫描线补充 (IC_QQQ) (感谢 \(IC\)_\(QQQ\) 大佬授以本内容的著作权.此人超然于世外,仅有 \(Luogu\) 账号 尚可膜拜) [学习笔记]线段树详解(全) ...

随机推荐

  1. java socket InputStream和OutputStream

    从java socket对象获取的InputSteam的read方法其实是对linux的recv()函数的调用,OutputStream也同理. 也就是说,InputStream和OutputStre ...

  2. SpringBoot-(1)-IDEA创建SpringBoot项目并运行访问接口

    一,安装IDEA mac安装IDEA IDEA配置Tomcat 二,创建SpringBoot项目 1,打开IDEA,点击Create New Project 2,选择自己所安装的JDK.如果没有配置J ...

  3. Objectvice-C中的super

    /** 狗:哈士奇 */ //僵尸 #import <Foundation/Foundation.h> @interface Dog : NSObject - (void) walk; + ...

  4. Android Weekly Notes Issue #241

    Android Weekly Issue #241 January 22nd, 2017 Android Weekly Issue #241 本期内容包括: 经典导航模式Master/Detail的设 ...

  5. malloc、calloc、realloc和alloca各种的区别

    需要先包含头文件 #include"malloc.h" malloc是标准的在堆中开辟新的空间 比如 char *pt=(char *)malloc(10*sizeof(char) ...

  6. Codeforces Round #340 (Div. 2) E. XOR and Favorite Number —— 莫队算法

    题目链接:http://codeforces.com/problemset/problem/617/E E. XOR and Favorite Number time limit per test 4 ...

  7. Codeforces Round #374 (Div. 2) B. Passwords —— 基础题

    题目链接:http://codeforces.com/contest/721/problem/B B. Passwords time limit per test 2 seconds memory l ...

  8. 配置Nginx四层负载均衡

    nginx 支持TCP转发和负载均衡的支持 实现下面的架构: 看配置: #user nobody; worker_processes 1; #error_log logs/error.log; #er ...

  9. YII的RBAC

    转自:http://www.cppblog.com/guojingjia2006/archive/2013/01/15/197298.html 开始准备 Yii提供了强大的配置机制和很多现成的类库.在 ...

  10. HihoCoder 1488 : 排队接水(莫队+树状数组)

    描述 有n个小朋友需要接水,其中第i个小朋友接水需要ai分钟. 由于水龙头有限,小Hi需要知道如果为第l个到第r个小朋友分配一个水龙头,如何安排他们的接水顺序才能使得他们等待加接水的时间总和最小. 小 ...