POJ 2482 Stars in Your Window (线段树+扫描线+区间最值,思路太妙了)

摘要:
如果遇到第2行,请添加-c,然后c+(-c)=0,这意味着星形不再位于矩形中。最后,注意数据将超过int,因此类型应该设置为longlong编写的第一个代码:#include<iostream>#include>studio。h˃ #include#include#include#definelsonrt˂˂1,L,mid#definersonrt˂˂1|1,mid+1,Rusingnamespacestd;组分最大值=20005;整数,w,h;longlongx,y,val;longlongyy[maxn];//存储纵坐标intidx的值//yy数组的下标映射<long long,int>hash//y坐标intcnt的映射//离散值structLine{longlongx,y1,y2;//y1=y,y2=y+h-1llonglongc;//亮度//按x从小到大排序。如果x相同,则先列出较小的c(即-c)线[maxn];StructNode{longlongsum;//存储最大longlongadd;}在这个区间树中[maxn˂˃1;build;buildvoidpushUp{tree[rt].sum=max;}voidpushDown{if{tree[rt˂˂1].add+=tree[rt].add;tree[t˂˂1|1].add+=tree[r].add;tree[rt˂˂1].sum+=tree[rt].add;tree[rt˂˃1;ifupdate;ifupdate;pushUp;}intmain(){while(scanf(“%d%d%d”,&n,&w,&h)!=yy[i-1])hashy[yy[i]]=++cnt;}n*=2;分类龙眼=0;生成;//为{update;ans=max;}逐个插入星号printf;}return0;}ViewCode稍后再次重写。我们没有使用map,而是使用离散化+二进制搜索离散值#include<iostream>#include˂csdio>#include˂algorithm>#include#include˂cmath>#definelsonrt<˂1,L,mid#definersonr

该题和 黑书 P102 采矿 类似

参考链接:
http://blog.csdn.net/shiqi_614/article/details/7819232
http://blog.csdn.net/tsaid/article/details/6686907
http://www.cnblogs.com/372465774y/archive/2012/07/28/2613272.html

题意:
  给你10000以内的星星的坐标和星星的亮度(即分别为x,y,c),要求用W*H的矩形去围住一个区域,
  使得这个区域内的星星的亮度最大,并且要求矩形边框上的星星不计入内。矩形可以平移,但不能旋转。

思路:

  这题我觉得的精妙之处就是将点转化成矩形,即对每一颗星星,画出以它为左下角的矩形,这个矩形就是它的影响范围。
  另外有一点需要注意,题目要求不包括矩形边上的点。
  但其实矩形下边(即y)和矩形左边(即x)这两边的星星可以算入进去,
  而矩形上边(即y+h)和矩形右边(即x+w)这两边的星星不能被算入。
  原因是只要把矩形往左下角移动那么一点点,就把下边和左边上的星星给包括进去了。
  因此一颗星星(x,y),它所能影响到的矩形的横轴区间为[x,x+w-1],纵轴区间为[y,y+h-1]

  所以为了方便处理,我们将每一颗星建立两条线line1(x,y,y+h-1,c),line2(x+w,y,y+h-1,-c)
  这样当我们不断插入星星的时候,其实就相当于有一个矩形框在从左往右移动,因为碰到 line1 则对应的影响区间[y,y+h-1]总亮度加上c,说明矩形中包含了该星星。
  碰到 line2 则再加上 -c, 那么 c + (-c ) = 0, 相当于该星星已不在矩形框内。
  那么,我们每插入一颗星就得到一个 宽度范围 固定(即w),但是 高度范围 不定(即h)的矩形。
  如此便只需要维护 y 坐标这一个变量了,让 [y,y+h-1] 这一区间加上c, 用线段树求得此时刻的最大值。
  当所有星星都插入完成,得到的最大值也就是我们要求的值了。

  还有一点是,对于排序的时候,若x相同,-c的要先放在前面。因为如果优先+c的边,
  那么位于x处的星星就会影响到x+w,而实际它是不能算入的。

  最后注意:数据会超int,所以类型要设成long long

 第一次写的代码:

POJ 2482 Stars in Your Window (线段树+扫描线+区间最值,思路太妙了)第1张POJ 2482 Stars in Your Window (线段树+扫描线+区间最值,思路太妙了)第2张
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <map>
#define lson rt<<1,L,mid
#define rson rt<<1|1,mid+1,R

using namespace std;
const int maxn=20005;
int n,w,h;
long long x,y,val;
long long yy[maxn];  //存储纵坐标的值
int idx; //yy数组的下标
map<long long,int> hashy;  //纵坐标y的映射
int cnt; //离散值

struct Line{
    long long x,y1,y2;  //y1=y,y2=y+h-1
    long long c;  //亮度
    //按照x从小到大排序,若x相同,则c小的(即-c)排在前面
    bool operator<(const Line tmp)const{
        if(x==tmp.x)
            return c<tmp.c;
        else
            return x<tmp.x;
    }
}line[maxn];

struct Node{
    long long sum;  //存储该区间中的最大值
    long long add;
}tree[maxn<<2];

void build(int rt,int L,int R){
    tree[rt].sum=tree[rt].add=0;
    if(L==R)
        return;
    int mid=(L+R)>>1;
    build(lson);
    build(rson);
}
void pushUp(int rt){
    tree[rt].sum=max(tree[rt<<1].sum,tree[rt<<1|1].sum);
}
void pushDown(int rt){
    if(tree[rt].add){
        tree[rt<<1].add+=tree[rt].add;
        tree[rt<<1|1].add+=tree[rt].add;
        tree[rt<<1].sum+=tree[rt].add;
        tree[rt<<1|1].sum+=tree[rt].add;
        tree[rt].add=0;
    }
}
void update(int rt,int L,int R,int l,int r,long long c){
    if(l<=L&&R<=r){
        tree[rt].sum+=c;
        tree[rt].add+=c;
        return;
    }
    pushDown(rt);
    int mid=(L+R)>>1;
    if(l<=mid)
        update(lson,l,r,c);
    if(r>mid)
        update(rson,l,r,c);
    pushUp(rt);
}

int main()
{
    while(scanf("%d%d%d",&n,&w,&h)!=EOF){
        idx=-1;
        for(int i=1;i<=n;i++){
            scanf("%I64d%I64d%I64d",&x,&y,&val);
            line[2*i-1].x=x;line[2*i-1].y1=y;line[2*i-1].y2=y+h-1;line[2*i-1].c=val;
            line[2*i].x=x+w;line[2*i].y1=y;line[2*i].y2=y+h-1;line[2*i].c=-val;
            yy[++idx]=y;
            yy[++idx]=y+h-1;
        }
        sort(yy,yy+idx+1);
        //对y进行离散化
        cnt=0;
        hashy[yy[0]]=++cnt;
        for(int i=1;i<=idx;i++){
            if(yy[i]!=yy[i-1])
                hashy[yy[i]]=++cnt;
        }
        n*=2;
        sort(line+1,line+n+1);
        long long ans=0;
        build(1,1,cnt);
        //将星星一颗一颗地插入
        for(int i=1;i<=n;i++){
            update(1,1,cnt,hashy[line[i].y1],hashy[line[i].y2],line[i].c);
            ans=max(tree[1].sum,ans);
        }
        printf("%I64d
",ans);

    }
    return 0;
}
View Code

 后来又重写了一遍,没用map,用的是离散化+二分查找离散值

POJ 2482 Stars in Your Window (线段树+扫描线+区间最值,思路太妙了)第3张POJ 2482 Stars in Your Window (线段树+扫描线+区间最值,思路太妙了)第4张
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define lson rt<<1,L,mid
#define rson rt<<1|1,mid+1,R
using namespace std;
const int maxn=10000+5;
int n,w,h;
int cnty,idy;
long long hashy[maxn<<1];

struct Line{
    long long x,y1,y2;
    int c;
    bool operator<(const Line tmp)const{
        if(x==tmp.x){
            return c<tmp.c;
        }
        else{
            return x<tmp.x;
        }
    }
}line[maxn<<1];

struct Node{
    long long sum;
    long long add;
}tree[maxn<<3];

void build(int rt,int L,int R){
    tree[rt].sum=tree[rt].add=0;
    if(L==R)
        return;
    int mid=(L+R)>>1;
    build(lson);
    build(rson);
}
void pushUp(int rt){
    tree[rt].sum=max(tree[rt<<1].sum,tree[rt<<1|1].sum);
}
void pushDown(int rt){
    if(tree[rt].add){
        tree[rt<<1].add+=tree[rt].add;
        tree[rt<<1|1].add+=tree[rt].add;
        tree[rt<<1].sum+=tree[rt].add;
        tree[rt<<1|1].sum+=tree[rt].add;
        tree[rt].add=0;
    }
}

void update(int rt,int L,int R,int l,int r,int c){
    if(l<=L&&R<=r){
        tree[rt].add+=c;
        tree[rt].sum+=c;
        return;
    }
    pushDown(rt);
    int mid=(L+R)>>1;
    if(l<=mid)
        update(lson,l,r,c);
    if(r>mid)
        update(rson,l,r,c);
    pushUp(rt);
}
int binarySearch(long long x){
    int l=0,r=idy+1,mid;
    while(r-l>1){
        mid=(l+r)>>1;
        if(hashy[mid]<=x)
            l=mid;
        else
            r=mid;
    }
    return l;
}
int main()
{
    long long x,y,c;
    while(scanf("%d%d%d",&n,&w,&h)!=EOF){
        cnty=1;
        for(int i=1;i<=n;i++){
            scanf("%lld%lld%lld",&x,&y,&c);
            line[2*i-1].x=x;line[2*i-1].y1=y;line[2*i-1].y2=y+h-1;line[2*i-1].c=c;
            line[2*i].x=x+w;line[2*i].y1=y;line[2*i].y2=y+h-1;line[2*i].c=-c;
            hashy[cnty++]=y;
            hashy[cnty++]=y+h-1;
        }
        n=n*2;
        sort(hashy+1,hashy+cnty);
        idy=1;
        for(int i=2;i<cnty;i++){
            if(hashy[i]!=hashy[i-1])
                hashy[++idy]=hashy[i];
        }
        sort(line+1,line+n+1);
        build(1,1,idy);
        long long ans=0;
        int a,b;
        for(int i=1;i<=n;i++){
            a=binarySearch(line[i].y1);
            b=binarySearch(line[i].y2);
            update(1,1,idy,a,b,line[i].c);
            ans=max(tree[1].sum,ans);
        }
        printf("%I64d
",ans);
    }
    return 0;
}
View Code

免责声明:文章转载自《POJ 2482 Stars in Your Window (线段树+扫描线+区间最值,思路太妙了)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇coding++:error Could not read JSON: Unexpected token (START_OBJECT), expected START_ARRAY: need JSON Array to contain As.WRAPPER_ARRAY type information for class java.lang.ObjectAndroid Learning:数据存储方案归纳与总结下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Atlantis(POJ1151+线段树+扫描线)

题目链接:http://poj.org/problem?id=1151 题目: 题意:求所有矩形的面积,重合部分只算一次。 思路:扫描线入门题,推荐几篇学扫描线的博客: 1.http://www.cnblogs.com/scau20110726/archive/2013/04/12/3016765.html 2.https://blog.csdn.ne...

可持久化数组入门

# 洛谷题目链接:[可持久化数组](https://www.luogu.org/problemnew/show/P3919) 题目描述 如题,你需要维护这样的一个长度为 NN 的数组,支持如下几种操作 在某个历史版本上修改某一个位置上的值 访问某个历史版本上的某一位置的值 此外,每进行一次操作(对于操作2,即为生成一个完全一样的版本,不作任何改动),...

洛谷P3833

Description 树链剖分板子题 考查两种操作 A u v w 把 u 节点到 v 节点路径上所有节点权值加 w Q u 求以 u 为根节点的子树权值之和 首先需要了解线段树和 dfs 序,我这里没有很好的链接,不熟悉的再自行百度吧 另外了解树链剖分的思想(重儿子等等),否则会出很多千奇百怪的错误 树链剖分的构成 DFS1 来处理每个点的...

线段树详解(原理、实现与应用)

线段树详解 By 岩之痕 目录: 一: 综述 二:原理 三:递归实现 四:非递归原理 五:非递归实现 六:线段树解题模型 七:扫描线 八:可持久化 (主席树) 九:练习题 一:综述 假设有编号从1到n的n个点,每个点都存了一些信息,用[L,R]表示下标从L到R的这些点。 线段树的用处就是,对编号连续的一些点进行修改或者统计操作,修改和统计的复杂度都...

[POJ1195] Mobile phones(二维树状数组)

题目链接:http://poj.org/problem?id=1195 题意:四种操作: 0:初始化一个S*S的零矩阵 1:点(x,y)是值+A 2:查询一个子矩阵里所有数的和 3:退出 线段树由于不能在两棵树之间传递标记,所以这种求和的操作非常难处理。 改学了一下而为树状数组,发现可是比二维线段树简单多了。 记得之前曾经看过zkw线段树的ppt讲稿,好像...

CF981E Addition on Segments(线段树分治+bitset)

观察本题,我们发现,如果某些操作每次都更新到了某个位置,那么我们可以通过维护bitset来发现这个对于这个位置来说的可能最大值 而且答案就是所有位置取一下或。因为我们发现对于每个位置,bitset上为1的那些数一定可以取到最大值。 但是这样过于暴力,我们发现这是一个区间操作,而区间操作一般和线段树相结合,因此采用线段树分治,先对这段操作影响到的区间打标记...