→传送窗口

(复制一下题面好了~)

题目背景

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

题目描述

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

输入输出格式

输入格式:

本题有多组数据,第一行为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. 各种数据库(oracle、mysql、sqlserver等)在Spring中数据源的配置和JDBC驱动包----转

    在开发基于数据库的应用系统时,需要在项目中进行数据源的配置来为数据 库的操作取得数据库连接.配置不同数据库的数据源的方法大体上都是相同的,不同的只是不同数据库的JDBC驱动类和连接URL以及相应的数据 ...

  2. [haoi2014]贴海报

    Bytetown城市要进行市长竞选,所有的选民可以畅所欲言地对竞选市长的候选人发表言论.为了统一管理,城市委员会为选民准备了一个张贴海报的electoral墙.张贴规则如下:1.electoral墙是 ...

  3. Codeforces Round #398 (Div. 2) C. Garland —— DFS

    题目链接:http://codeforces.com/contest/767/problem/C 题解:类似于提着一串葡萄,用剪刀剪两条藤,葡萄分成了三串.问怎样剪才能使三串葡萄的质量相等. 首先要做 ...

  4. Spring注解原理的详细剖析与实现

    本文主要分为三部分: 一. 注解的基本概念和原理及其简单实用 二. Spring中如何使用注解 三. 编码剖析spring@Resource的实现原理 一.注解的基本概念和原理及其简单实用 注解(An ...

  5. The import ....cannot be resolved 解决方法

    1:右击项目build path>configure build path>libraries看有没感叹号什么的不正常的lib,移除掉 2:点击项目的build path>confi ...

  6. 配置react+webpack+es6中的一些教训

    1.要用es6,因为目前浏览器的支持情况,那么肯定需要插件将e6的代码转换成es5,我用的是babel-loader,事实证明使用6.x版本似乎是不行的,我换成5.3.2之后就成功了. 2.webpa ...

  7. Opencv— — mix channels

    // define head function #ifndef PS_ALGORITHM_H_INCLUDED #define PS_ALGORITHM_H_INCLUDED #include < ...

  8. 51nod-1065:最小正子段和(STL)

    N个整数组成的序列a11,a22,a33,…,ann,从中选出一个子序列(aii,ai+1i+1,…ajj),使这个子序列的和>0,并且这个和是所有和>0的子序列中最小的. 例如:4,-1 ...

  9. codevs 3012 线段覆盖4

    传送门 3012 线段覆盖 4  时间限制: 1 s  空间限制: 64000 KB  题目等级 : 黄金 Gold   题目描述 Description 数轴上有n条线段,线段的两端都是整数坐标,坐 ...

  10. js中this 的四种用法

    this 在函数执行时,this 总是指向调用该函数的对象.要判断 this 的指向,其实就是判断 this 所在的函数属于谁. 在<javaScript语言精粹>这本书中,把 this  ...