poj2482 Stars in Your Window(成段更新+扫描线)
2016-05-19 20:39
369 查看
http://poj.org/problem?id=2482
题意:给你n个星星的x,y,val,求用一个长w宽h圈住的最大亮度的值(还有这题前缀长的不忍直视啊)。
思路:这题关键点在于对问题的转化,按照最笨的暴力枚举只会超时。这里我们设刚开始给的框代号X,以ABC点为中心临时做出来的框为代号ABC...。我们知道一个矩形的中心点可以代表它的位置,那么以A为中心,作w、h的矩形A,此矩形的范围表示框X的中心点在这个范围内即可圈住该点。设想如果有两个矩形A和B有交集,那么交集部分表示既可以圈住A点,也可以圈住B点,所以任意矩形的交集表示可以圈住任意的点。那么这里求框内最大亮度就转化成了求覆盖面积的最大值。
这样的话就是成段更新求最值+扫描线的思路了。那么点如何代表矩形呢?按我们上面的思路是按照点为中心做矩形,这里直接将横坐标平移w个单位,所有点都平移效果不会变。离散纵坐标值,扫描线从左往右扫描。还要注意这里做出的矩形是有权值的,一条线段映射到线段树里就是成段更新,lazy也可以用上。
#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <string.h>
#include <iostream>
using namespace std;
typedef long long LL;
const int N = 100010;
const int INF = 1e8;
struct line
{
__int64 l, r;
__int64 sum;
__int64 add;
}tree[8*N];
struct node
{
__int64 w, h;
__int64 val;
bool operator < (const struct node & tmp) const
{
if(w == tmp.w)
return val < tmp.val;
return w < tmp.w;
}
}point[8*N];
__int64 y[N*8];
void build(__int64 i, __int64 l, __int64 r)
{
tree[i].l = l;
tree[i].r = r;
tree[i].add = 0;
tree[i].sum = 0;
if(l == r)
{
return;
}
__int64 mid = (l+r) >> 1;
build(i*2, l, mid);
build(i*2+1, mid+1, r);
}
__int64 binsearch(__int64 key, __int64 k)
{
__int64 high = k;
__int64 low = 1;
while(high >= low)
{
__int64 mid = (high+low) >> 1;
if(y[mid] == key)
{
return mid;
}
else if(y[mid] < key)
{
low = mid+1;
}
else high = mid-1;
}
return -1;
}
void update(__int64 i, __int64 l, __int64 r, __int64 val)
{
if(tree[i].l == l && tree[i].r == r)
{
tree[i].add += val;
tree[i].sum += val;
return;
}
if(tree[i].add)
{
tree[i*2].add += tree[i].add;
tree[i*2+1].add += tree[i].add;
tree[i*2].sum += tree[i].add;
tree[i*2+1].sum += tree[i].add;
tree[i].add = 0;
}
__int64 mid = (tree[i].l+tree[i].r) >> 1;
if(mid >= r)
update(i*2, l, r, val);
else if(mid < l)
update(i*2+1, l, r, val);
else
{
update(i*2, l, mid, val);
update(i*2+1, mid+1, r, val);
}
tree[i].sum = max(tree[i*2].sum, tree[i*2+1].sum);
}
int main()
{
// freopen("in.txt", "r", stdin);
__int64 n, w, h;
while(~scanf("%I64d%I64d%I64d", &n, &w, &h))
{
for(__int64 i = 1; i <= n; i++)
{
scanf("%I64d%I64d%I64d", &point[i].w, &point[i].h, &point[i].val);
y[i] = point[i].h;
y[i+n] = point[i].h+h;
point[i+n].w = point[i].w+w;
point[i+n].h = point[i].h;
point[i+n].val = -point[i].val;
}
sort(point+1, point+1+n*2);
sort(y+1, y+1+n*2);
__int64 k = 1;
for(__int64 i = 2; i <= n*2; i++)
{
if(y[i-1] != y[i])
{
y[++k] = y[i];
}
}
build(1, 1, k);
__int64 ans = 0;
for(__int64 i = 1; i <= n*2; i++)
{
__int64 l = binsearch(point[i].h, k);
__int64 r = binsearch(point[i].h+h, k)-1;
if(l > r) swap(l, r);
// printf("%I64d %I64d\n", l, r);
update(1, l, r, point[i].val);
ans = max(ans, tree[1].sum);
}
printf("%I64d\n", ans);
}
return 0;
}
题意:给你n个星星的x,y,val,求用一个长w宽h圈住的最大亮度的值(还有这题前缀长的不忍直视啊)。
思路:这题关键点在于对问题的转化,按照最笨的暴力枚举只会超时。这里我们设刚开始给的框代号X,以ABC点为中心临时做出来的框为代号ABC...。我们知道一个矩形的中心点可以代表它的位置,那么以A为中心,作w、h的矩形A,此矩形的范围表示框X的中心点在这个范围内即可圈住该点。设想如果有两个矩形A和B有交集,那么交集部分表示既可以圈住A点,也可以圈住B点,所以任意矩形的交集表示可以圈住任意的点。那么这里求框内最大亮度就转化成了求覆盖面积的最大值。
这样的话就是成段更新求最值+扫描线的思路了。那么点如何代表矩形呢?按我们上面的思路是按照点为中心做矩形,这里直接将横坐标平移w个单位,所有点都平移效果不会变。离散纵坐标值,扫描线从左往右扫描。还要注意这里做出的矩形是有权值的,一条线段映射到线段树里就是成段更新,lazy也可以用上。
#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <string.h>
#include <iostream>
using namespace std;
typedef long long LL;
const int N = 100010;
const int INF = 1e8;
struct line
{
__int64 l, r;
__int64 sum;
__int64 add;
}tree[8*N];
struct node
{
__int64 w, h;
__int64 val;
bool operator < (const struct node & tmp) const
{
if(w == tmp.w)
return val < tmp.val;
return w < tmp.w;
}
}point[8*N];
__int64 y[N*8];
void build(__int64 i, __int64 l, __int64 r)
{
tree[i].l = l;
tree[i].r = r;
tree[i].add = 0;
tree[i].sum = 0;
if(l == r)
{
return;
}
__int64 mid = (l+r) >> 1;
build(i*2, l, mid);
build(i*2+1, mid+1, r);
}
__int64 binsearch(__int64 key, __int64 k)
{
__int64 high = k;
__int64 low = 1;
while(high >= low)
{
__int64 mid = (high+low) >> 1;
if(y[mid] == key)
{
return mid;
}
else if(y[mid] < key)
{
low = mid+1;
}
else high = mid-1;
}
return -1;
}
void update(__int64 i, __int64 l, __int64 r, __int64 val)
{
if(tree[i].l == l && tree[i].r == r)
{
tree[i].add += val;
tree[i].sum += val;
return;
}
if(tree[i].add)
{
tree[i*2].add += tree[i].add;
tree[i*2+1].add += tree[i].add;
tree[i*2].sum += tree[i].add;
tree[i*2+1].sum += tree[i].add;
tree[i].add = 0;
}
__int64 mid = (tree[i].l+tree[i].r) >> 1;
if(mid >= r)
update(i*2, l, r, val);
else if(mid < l)
update(i*2+1, l, r, val);
else
{
update(i*2, l, mid, val);
update(i*2+1, mid+1, r, val);
}
tree[i].sum = max(tree[i*2].sum, tree[i*2+1].sum);
}
int main()
{
// freopen("in.txt", "r", stdin);
__int64 n, w, h;
while(~scanf("%I64d%I64d%I64d", &n, &w, &h))
{
for(__int64 i = 1; i <= n; i++)
{
scanf("%I64d%I64d%I64d", &point[i].w, &point[i].h, &point[i].val);
y[i] = point[i].h;
y[i+n] = point[i].h+h;
point[i+n].w = point[i].w+w;
point[i+n].h = point[i].h;
point[i+n].val = -point[i].val;
}
sort(point+1, point+1+n*2);
sort(y+1, y+1+n*2);
__int64 k = 1;
for(__int64 i = 2; i <= n*2; i++)
{
if(y[i-1] != y[i])
{
y[++k] = y[i];
}
}
build(1, 1, k);
__int64 ans = 0;
for(__int64 i = 1; i <= n*2; i++)
{
__int64 l = binsearch(point[i].h, k);
__int64 r = binsearch(point[i].h+h, k)-1;
if(l > r) swap(l, r);
// printf("%I64d %I64d\n", l, r);
update(1, l, r, point[i].val);
ans = max(ans, tree[1].sum);
}
printf("%I64d\n", ans);
}
return 0;
}
相关文章推荐
- 初学ACM - 组合数学基础题目PKU 1833
- POJ ACM 1001
- POJ ACM 1002
- 1611:The Suspects
- POJ1089 区间合并
- POJ 2159 Ancient Cipher
- POJ 2635 The Embarrassed Cryptographe
- POJ 3292 Semi-prime H-numbers
- POJ 2773 HAPPY 2006
- POJ 3090 Visible Lattice Points
- POJ-2409-Let it Bead&&NYOJ-280-LK的项链
- POJ-1695-Magazine Delivery-dp
- POJ1523 SPF dfs
- POJ-1001 求高精度幂-大数乘法系列
- POJ-1003 Hangover
- POJ-1004 Financial Management
- POJ1050 最大子矩阵和
- 用单调栈解决最大连续矩形面积问题
- 2632 Crashing Robots的解决方法
- 1573 Robot Motion (简单题)