线段树+扫描线两题hdu1542 hdu1828

原创 2015年11月21日 11:03:22

hdu1542 Atlantis

题意很简单就是给几个矩形的左下角坐标及右上角左边。求这几个矩形覆盖到的面积。
初学扫描线,太渣了各种不会,搜博客看到的都是粘贴别人的,无奈用了一个周六才完成。
这个题的思路大概是对纵坐标离散 建立线段树。依次插入排序后的竖边。iff为1则为入边,为0则为出边.面积等于每次插入时两个竖边距离与当前线段树中总长度的积之和。
我的渣渣代码:

#include <cstdio>
#include <cstring>
#include <cctype>
#include <cmath>
#include <set>
#include <map>
#include <list>
#include <queue>
#include <deque>
#include <stack>
#include <string>
#include <bitset>
#include <vector>
#include <iostream>
#include <algorithm>
#define LL __int64
#define INF 0x3f3f3f3f
#define maxn 100005
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define Mid(a,b) (((a)+(b))/2)
using namespace std;
struct Node
{
    int l,r;
    int lnum,rnum,mnum;
    int  cover;
    Node *pleft,*pright;
};
Node tree[maxn];
int Ncount;
void Build(Node *root,int l,int r)
{
    root->cover=0;
    root->l=l;
    root->r=r;
    root->mnum=root->lnum=root->rnum=r-l+1;
    if(l==r)
        return ;
    Ncount++;
    root->pleft=tree+Ncount;
    Ncount++;
    root->pright=tree+Ncount;
    Build(root->pleft,l,(l+r)/2);
    Build(root->pright,(l+r)/2+1,r);
}
int Ques(Node *root,int n)
{
    if(root->l==root->r)
        return root->l;
    if(root->cover)//0 no operate
    {
        root->pright->cover=root->pleft->cover=root->cover;
        if(root->cover==1)//1 be full
        {
            root->pright->lnum=root->pright->rnum=root->pright->mnum=0;
            root->pleft->lnum=root->pleft->rnum=root->pleft->mnum=0;
        }
        else //be empty
        {
            root->pright->lnum=root->pright->rnum=root->pright->mnum=root->pright->r-root->pright->l+1;
            root->pleft->lnum=root->pleft->rnum=root->pleft->mnum=root->pleft->r-root->pleft->l+1;
        }
        root->cover=0;
    }
    if(n<=root->pleft->mnum)
        return Ques(root->pleft,n);
    else if(n<=root->pleft->rnum+root->pright->lnum)
        return Mid(root->l,root->r)-root->pleft->rnum+1;
    else
        return Ques(root->pright,n);
}
void Update(Node *root,int a,int b,int op)
{
    if(a==root->l&&b==root->r)
    {
        root->cover=op;
        if(op==1)
            root->lnum=root->mnum=root->rnum=0;
        else
            root->lnum=root->mnum=root->rnum=root->r-root->l+1;
        return ;
    }
     if(root->cover)
    {
        root->pright->cover=root->pleft->cover=root->cover;
        if(root->cover==1)
        {
            root->pright->lnum=root->pright->rnum=root->pright->mnum=0;
            root->pleft->lnum=root->pleft->rnum=root->pleft->mnum=0;
        }
        else
        {
            root->pright->lnum=root->pright->rnum=root->pright->mnum=root->pright->r-root->pright->l+1;
            root->pleft->lnum=root->pleft->rnum=root->pleft->mnum=root->pleft->r-root->pleft->l+1;
        }
        root->cover=0;
    }
    if(b<=Mid(root->l,root->r))
        Update(root->pleft,a,b,op);
    else if(a>Mid(root->l,root->r))
        Update(root->pright,a,b,op);
    else
    {
        Update(root->pleft,a,Mid(root->l,root->r),op);
        Update(root->pright,Mid(root->l,root->r)+1,b,op);
    }
    root->lnum=root->pleft->lnum;
    root->rnum=root->pright->rnum;
    if(root->lnum==root->pleft->r-root->pleft->l+1)
        root->lnum+=root->pright->lnum;
    if(root->rnum==root->pright->r-root->pright->l+1)
        root->rnum+=root->pleft->rnum;
    root->mnum=Max(root->pright->mnum,root->pleft->mnum);
    root->mnum=Max(root->mnum,root->pleft->rnum+root->pright->lnum);
}
int main()
{
    int n,q,a,b,s;
    scanf("%d%d",&n,&q);
    Ncount=0;
    Build(tree,1,n);
    while(q--)
    {
        scanf("%d",&s);
        if(s==1)
        {
            scanf("%d",&a);
            if(a<=tree->mnum)
            {
            int ans=Ques(tree,a);
            Update(tree,ans,ans+a-1,1);
            printf("%d\n",ans);
            }
            else
                puts("0");
        }
        else
        {
            scanf("%d%d",&a,&b);
            Update(tree,a,a+b-1,-1);
        }
    }
    return 0;
}

hdu1828 Picture
求几个矩形的合并后的周长,直接用线段树记录已有竖边长度及线段个数。
周长等于每次插入竖边时总长变化差的绝对值之和+线段横坐标只差乘以线段个数之和。
很多需要注意的地方,如 是多组数据。。。

#include <cstdio>
#include <cstring>
#include <cctype>
#include <cmath>
#include <set>
#include <map>
#include <list>
#include <queue>
#include <deque>
#include <stack>
#include <string>
#include <bitset>
#include <vector>
#include <iostream>
#include <algorithm>
#define LL __int64
#define INF 0x3f3f3f3f
#define maxn 105
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define Mid(a,b) (((a)+(b))/2)
#define lson root<<1,l,mid
#define rson root<<1|1,mid,r
using namespace std;
struct Node
{
    int l,r,cover,len,num,ls,rs;
};
struct Line
{
    int x,yu,yd;
    int cover;
};
Node tree[60000];
Line line[60000];
int yy[60000];
int pla[60005];
bool cmp(Line a,Line b)
{
    if(a.x==b.x)
        return a.cover>b.cover;
    else
        return a.x<b.x;
}
void Build(int root , int l,int r)
{
    tree[root].l=l;
    tree[root].r=r;
    tree[root].len=tree[root].cover=tree[root].num=tree[root].ls=tree[root].rs=0;
    if(l+1==r)
        return;
    int mid=Mid(l,r);
    Build(lson);
    Build(rson);
}
void Push(int root)
{
    if(tree[root].cover)
    {
        tree[root].len=yy[tree[root].r]-yy[tree[root].l];
        tree[root].num=1;
        tree[root].rs=tree[root].ls=1;
    }
    else if(tree[root].r-tree[root].l==1)
    {
        tree[root].len=0;
        tree[root].num=0;
        tree[root].rs=tree[root].ls=0;
    }
    else
    {
        tree[root].len=tree[root<<1].len+tree[root<<1|1].len;
        tree[root].rs=tree[root<<1|1].rs;
        tree[root].ls=tree[root<<1].ls;
        tree[root].num=tree[root<<1].num+tree[root<<1|1].num;
        if(tree[root<<1].rs&&tree[root<<1|1].ls)
            tree[root].num-=1;
    }
}

void Update(int root,int l,int r,int cover)
{
    if(r<tree[root].l||l>tree[root].r)
        return ;
    if(l<=tree[root].l&&r>=tree[root].r)
    {
        tree[root].cover+=cover;
        Push(root);
        return ;
    }
    Update(root<<1,l,r,cover);
    Update(root<<1|1,l,r,cover);
    Push(root);
}
int main()
{
    int n;
    while(scanf("%d",&n)==1)
    {
        if(n==0)
        {
            printf("0\n");
            continue;
        }
    int con=0;
    int x1,x2,y1,y2;
    for(int i=1; i<=n; i++)
    {
        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
        line[con].yu=y2;
        line[con].yd=y1;
        line[con].x=x1;
        line[con].cover=1;
        yy[con++]=y1;

        line[con].yu=y2;
        line[con].yd=y1;
        line[con].x=x2;
        line[con].cover=-1;
        yy[con++]=y2;
    }
    stable_sort(line,line+con,cmp);
    stable_sort(yy,yy+con);
    int num=unique(yy,yy+con)-yy;
    for(int i=0; i<num; i++)
        pla[yy[i]+20000]=i;
    Build(1,0,num-1);
    int lastl=0;
    long long  res=0;
    for(int i=0; i<con; i++)
    {
        int foo=1;
        if(tree[1].len) res+=(line[i].x-line[i-1].x)*tree[1].num*2;
        Update(1,pla[line[i].yd+20000],pla[line[i].yu+20000],line[i].cover);
        while(line[i+1].x==line[i].x)
        {
            if(foo&&line[i+1].cover==line[i].cover)
            {
                Update(1,pla[line[i+1].yd+20000],pla[line[i+1].yu+20000],line[i+1].cover);
                i++;
            }
            else if(foo&&line[i+1].cover!=line[i].cover)
            {
                foo=0;
                res+=abs(lastl-tree[1].len);
                lastl=tree[1].len;
                Update(1,pla[line[i+1].yd+20000],pla[line[i+1].yu+20000],line[i+1].cover);
                i++;
            }
            else
            {
                Update(1,pla[line[i+1].yd+20000],pla[line[i+1].yu+20000],line[i+1].cover);
                i++;
            }
        }
        res+=abs(lastl-tree[1].len);
        lastl=tree[1].len;
    }
    res+=abs(lastl);
    printf("%lld\n",res);
     }

    return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

算法总结:【线段树+扫描线】&矩形覆盖求面积/周长问题(HDU 1542/HDU 1828)

问题:给出若干个矩形,(给的是矩形左上角和右下角坐标),求最后所得图形的面积/周长; 三个矩形如左图所示,而若要计算面积,看右图,用3个矩形各自的面积之和减去重复部分(红色和蓝色)的面积 人算很简单...

hdu 1828线段树扫描线求周长并

#include #include #include #include #include #include #include #include #include #include #include #...

HDU 1828 && POJ 1177 Picture(线段树+扫描线+离散化)

HDU题目地址:HDU 1828  POJ题目地址:POJ 1177 这题是求周长并,我用的方法可能有点麻烦。。是先求横着的线,再求竖着的线。每次只要求出每次的总区间覆盖长度,然后每次累加这次的总区...

poj 1177 || HDU 1828 Picture (线段树扫描线求 图形并的周长)

Problem Description A number of rectangular posters, photographs and other pictures of the same sha...

hdu1828-Picture 线段树+扫描线 求周长并

Picture Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Su...

hdu 1828 线段树+扫描线

矩形周长和~ #include #include #include #include #define lson pos

hdu1828 Picture (线段树+扫描线)(求周长并)

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1828 题意:给定n(n Picture Time Limit: 6000/2000 MS (...
  • w20810
  • w20810
  • 2016年02月28日 19:45
  • 264

hdu1828&poj1177(线段树求矩形交周长,扫描线)

题目链接:hdu1828

HDU 1828 线段树之扫描线之周长并

点击打开链接 题意:给n个矩形,求它们重叠后的周长 思路:用线段树的扫描线从下到上扫一遍,与面积并思想有些相似面积并,下面重边的处理相似,但是周长的并需要求的是竖边的个数然后乘以高度,而面积并求的...
  • Dan__ge
  • Dan__ge
  • 2016年03月25日 11:41
  • 577

HDU 1828 Picture(线段树 + 扫描线)

题目链接:点击打开链接 题意:求n个矩形的周长的并。 思路:用扫描线法, 按照x坐标和y坐标分别扫描, 用线段树维护区间覆盖情况, yy了一下, 可以发现, 每次的可见轮廓都等于这次的区间覆盖长度...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:线段树+扫描线两题hdu1542 hdu1828
举报原因:
原因补充:

(最多只允许输入30个字)