POJ 2482 Stars in Your Window (线段树扫描线)

2024-08-21 08:08

本文主要是介绍POJ 2482 Stars in Your Window (线段树扫描线),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


题意:

给定n个星星的坐标(x,y)以及亮度c ,求用一个宽W,高H的框(不含边界),能框住的星星的亮度总和的最大值为多少。

( 0<= x,y <2^31 , 1<=c<=100    , 1<=W , H <= 1000000    ,   x,y,c,W,H都是整数)

思路:

用矩形右上角坐标(X,Y)来代表矩形位置,原问题等价于,X,Y为整数,用一个宽W,高H的框(不含左,下边界),能框住的星星的亮度总和的最大值为多少。因为,若X,Y为整数,并且四边上都有星星,那么将该方框向右和上分别平移1/2个单位,就可以在不丢失框内星星的情况下框进上边框和右边框的星星。


转换之后,对于星星(x,y),矩形的右上角坐标的范围在 x-[x,x+W), y-[y,y+H) 这个区域内时,算作框进了这颗星星,要算上这颗星星的亮度。


于是,星星变成了带权值的矩形,矩形框变成了点,问题就是在矩形的重合图中,找到权值最大的点。

这就可以用线段树扫描线了,就是,用一条垂直于x轴的线来从左到右扫描整个图形。整个扫描过程中,线上权值最大的一点就是答案。

线上的权值需要进行区间修改以及维护最大值,这里就用线段树来储存。

将Y值离散化(去除重复值),然后,将星星先根据X值,再根据Y值排序。

然后不断将新的矩形加入,旧的矩形删除就行了。


#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define  inf  0x1fffffff
#define maxn 20007
#define LL long long
using namespace std;
//SBT 离散化 
LL Rank[maxn],Rn;
void SetRank(){sort(Rank+1,Rank+1+Rn); int I=1;for(int i=2;i<=Rn;++i) if(Rank[i]!=Rank[i-1]) Rank[++I]=Rank[i];Rn=I;
} 
int GetRank(LL x){int L=1,R=Rn,M;//[L,R] first >=xwhile(L!=R){M=(L+R)>>1;if(Rank[M]<x) L=M+1;else R=M;}return L;
}
//储存数据 
struct Star{//记录星星,之后要排序 LL x,y;int c;Star(){}Star(LL x,LL y,int c):x(x),y(y),c(c){}bool operator < (const Star &B)const{return x < B.x|| x==B.x && y < B.y;}
}St[maxn>>1];
int n,W,H;
//线段树 区间加&&最大值 
int Max[maxn<<2],Add[maxn<<2];
void PushUp(int rt){Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);
}
void PushDown(int rt){if(Add[rt]){Add[rt<<1]+=Add[rt];Add[rt<<1|1]+=Add[rt];Max[rt<<1]+=Add[rt];Max[rt<<1|1]+=Add[rt];Add[rt]=0;}
}
void Update(int L,int R,int C,int l,int r,int rt){if(L <=l && r <= R){Add[rt]+=C;Max[rt]+=C;return;}PushDown(rt);int m=(l+r)>>1;if(L <= m) Update(L,R,C,l,m,rt<<1);if(R >  m) Update(L,R,C,m+1,r,rt<<1|1); PushUp(rt);
}
int main(void)
{while(~scanf("%d%d%d",&n,&W,&H)){memset(Max,0,sizeof(Max));memset(Add,0,sizeof(Add));Rn=0;for(int i=1;i<=n;++i) {scanf("%I64d%I64d%d",&St[i].x,&St[i].y,&St[i].c);Rank[++Rn]=St[i].y;Rank[++Rn]=St[i].y+H;}SetRank();sort(St+1,St+n+1);//给星星排序 int L=1,X,ANS=0;for(int i=1;i<=n;++i){Update(GetRank(St[i].y),GetRank(St[i].y+H)-1,St[i].c,1,Rn,1);//加入新矩形 X=St[i].x;//更新当前X while(St[L].x+W <= X){//删除已经对横坐标为X的扫描线无影响的矩形 Update(GetRank(St[L].y),GetRank(St[L].y+H)-1,-St[L].c,1,Rn,1);++L;}ANS=max(ANS,Max[1]);//求最大值 }printf("%d\n",ANS);//输出答案 }
return 0;
}




这篇关于POJ 2482 Stars in Your Window (线段树扫描线)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1092599

相关文章

Window Server创建2台服务器的故障转移群集的图文教程

《WindowServer创建2台服务器的故障转移群集的图文教程》本文主要介绍了在WindowsServer系统上创建一个包含两台成员服务器的故障转移群集,文中通过图文示例介绍的非常详细,对大家的... 目录一、 准备条件二、在ServerB安装故障转移群集三、在ServerC安装故障转移群集,操作与Ser

Window Server2016加入AD域的方法步骤

《WindowServer2016加入AD域的方法步骤》:本文主要介绍WindowServer2016加入AD域的方法步骤,包括配置DNS、检测ping通、更改计算机域、输入账号密码、重启服务... 目录一、 准备条件二、配置ServerB加入ServerA的AD域(test.ly)三、查看加入AD域后的变

Window Server2016 AD域的创建的方法步骤

《WindowServer2016AD域的创建的方法步骤》本文主要介绍了WindowServer2016AD域的创建的方法步骤,文中通过图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价... 目录一、准备条件二、在ServerA服务器中常见AD域管理器:三、创建AD域,域地址为“test.ly”

poj3468(线段树成段更新模板题)

题意:包括两个操作:1、将[a.b]上的数字加上v;2、查询区间[a,b]上的和 下面的介绍是下解题思路: 首先介绍  lazy-tag思想:用一个变量记录每一个线段树节点的变化值,当这部分线段的一致性被破坏我们就将这个变化值传递给子区间,大大增加了线段树的效率。 比如现在需要对[a,b]区间值进行加c操作,那么就从根节点[1,n]开始调用update函数进行操作,如果刚好执行到一个子节点,

hdu1394(线段树点更新的应用)

题意:求一个序列经过一定的操作得到的序列的最小逆序数 这题会用到逆序数的一个性质,在0到n-1这些数字组成的乱序排列,将第一个数字A移到最后一位,得到的逆序数为res-a+(n-a-1) 知道上面的知识点后,可以用暴力来解 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#in

hdu1689(线段树成段更新)

两种操作:1、set区间[a,b]上数字为v;2、查询[ 1 , n ]上的sum 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<queue>#include<set>#include<map>#include<stdio.h>#include<stdl

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

hdu 2602 and poj 3624(01背包)

01背包的模板题。 hdu2602代码: #include<stdio.h>#include<string.h>const int MaxN = 1001;int max(int a, int b){return a > b ? a : b;}int w[MaxN];int v[MaxN];int dp[MaxN];int main(){int T;int N, V;s

poj 1511 Invitation Cards(spfa最短路)

题意是给你点与点之间的距离,求来回到点1的最短路中的边权和。 因为边很大,不能用原来的dijkstra什么的,所以用spfa来做。并且注意要用long long int 来存储。 稍微改了一下学长的模板。 stack stl 实现代码: #include<stdio.h>#include<stack>using namespace std;const int M

poj 3259 uva 558 Wormholes(bellman最短路负权回路判断)

poj 3259: 题意:John的农场里n块地,m条路连接两块地,w个虫洞,虫洞是一条单向路,不但会把你传送到目的地,而且时间会倒退Ts。 任务是求你会不会在从某块地出发后又回来,看到了离开之前的自己。 判断树中是否存在负权回路就ok了。 bellman代码: #include<stdio.h>const int MaxN = 501;//农场数const int