zoukankan      html  css  js  c++  java
  • poj1151 Atlantis——扫描线+线段树

    题目:http://poj.org/problem?id=1151

    经典的扫描线问题;

    可以用线段树的每个点代表横向被矩形上下边分割开的每一格,这样将一个矩形的出现或消失化为线段树上的单点修改;

    每个格子记录两个值:c(矩形存在情况),sum(对当前答案作出贡献的长度);

    将y离散化作为建树的依据;

    一开始没想到线段树上的点应该是横向的格子,写了个乱七八糟:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int t,n,xt;
    double s[805],ans,tr[805],mx,eps=0.36;
    struct P{
        double x,y1,y2;
        int tp;
        P(int x=0,int y1=0,int y2=0,int t=0):x(x),y1(y1),y2(y2),tp(t) {}
    }p[805];
    void pushup(int x)
    {
        tr[x]=tr[x<<1]+tr[x<<1|1];
    }
    void add(int x,double l,double r,double L,double R,int w)
    {
    //    cout<<x<<endl;
    //    printf("l=%lf r=%lf eps=%lf
    ",l,r,eps);
        if(r-l<eps)
        {
            s[x]+=w;
            if(s[x])tr[x]=1;
            else tr[x]=0;
    //        printf("s[%d]=%d
    ",x,s[x]);
            return;
        }
        double mid=(l+r)/2;
        if(mid>=L)add(x<<1,l,mid,L,R,w);
        if(mid<R)add(x<<1|1,mid+1,r,L,R,w);
        pushup(x);
    }
    bool cmp(P x,P y){return x.x<y.x;}
    int main()
    {
        while(scanf("%d",&n)==1)
        {
            t++;xt=0;mx=0;ans=0;
            memset(tr,0,sizeof tr);
            memset(s,0,sizeof s);
            if(!n)return 0;
            for(int i=1;i<=n;i++)
            {
                xt++;scanf("%lf%lf",&p[xt].x,&p[xt].y1);
                xt++;scanf("%lf%lf",&p[xt].x,&p[xt].y1);
                p[xt-1].y2=p[xt].y1;p[xt].y2=p[xt-1].y1;
                p[xt-1].tp=1;p[xt].tp=-1;
                mx=max(mx,max(p[xt].y1,p[xt].y2));
            }
            sort(p+1,p+xt+1,cmp);
            double lst=-1;
            for(int i=1;i<=xt;i++)
            {
                if(p[i].y1>p[i].y2)swap(p[i].y1,p[i].y2);
                add(1,0,mx,p[i].y1,p[i].y2,p[i].tp);
                if(lst!=-1)ans+=(p[i].x-lst)*tr[1];
                lst=p[i].x;
            }
            printf("Test case #%d
    Total explored area: %.2lf 
    ",t,ans);
        }
        return 0;
    }

    然后参考别人的博客,努力理解了半天,模仿着打了出来,终于A了...

    学到了add()函数里面那种二分的方法。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int n,ct,t;
    double ans,y[205];
    struct P{
        int l,r,c;//c为上下矩形抵消数 
        double ly,ry,sum;//sum为此时计入计算的长度 
    }tr[805];
    struct E{
        int tp;
        double x,ly,ry;
    }ed[205];
    bool cmp(E x,E y){return x.x<y.x;}
    void build(int x,int l,int r)
    {
        tr[x].l=l;tr[x].r=r;
        tr[x].ly=y[l];tr[x].ry=y[r];
        tr[x].c=0;tr[x].sum=0;
        if(l==r-1)return;
        int mid=(l+r)>>1;
        build(x<<1,l,mid);
        build(x<<1|1,mid,r);//不是mid+1,因为l,r表示此块上下两边 
    }
    void pushup(int x)
    {
        if(tr[x].c>0)//全选
            tr[x].sum=tr[x].ry-tr[x].ly; 
        else if(tr[x].l==tr[x].r-1)//仅有一格且被退出 
             tr[x].sum=0;
        else//可能有其他边覆盖 
            tr[x].sum=tr[x<<1].sum+tr[x<<1|1].sum;
    }
    void add(int x,E e)
    {
        if(tr[x].ly==e.ly&&tr[x].ry==e.ry)
        {
            tr[x].c+=e.tp;
            pushup(x);
            return;
        }
        if(tr[x<<1].ry>=e.ry)add(x<<1,e);
        else if(tr[x<<1|1].ly<=e.ly)add(x<<1|1,e);
        else
        {
            E tmp=e;
            tmp.ry=tr[x<<1].ry;
            add(x<<1,tmp);
            tmp=e;
            tmp.ly=tr[x<<1|1].ly;
            add(x<<1|1,tmp);
        }
        pushup(x);
    }
    int main()
    {
        while(scanf("%d",&n)==1)
        {
            t++;
            if(!n)return 0;
            ct=0;ans=0;
            for(int i=1;i<=n;i++)
            {
                double x1,y1,x2,y2;
                scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
                y[++ct]=y1;ed[ct].tp=1;
                ed[ct].x=x1;ed[ct].ly=y1;ed[ct].ry=y2;
                y[++ct]=y2;ed[ct].tp=-1;
                ed[ct].x=x2;ed[ct].ly=y1;ed[ct].ry=y2;
            }
            sort(ed+1,ed+ct+1,cmp);
            sort(y+1,y+ct+1);
            build(1,1,ct);
            add(1,ed[1]);
            for(int i=2;i<=ct;i++)
            {
                ans+=tr[1].sum*(ed[i].x-ed[i-1].x);
                add(1,ed[i]);//上下勿反 
            }
            printf("Test case #%d
    Total explored area: %.2f
    
    ",t,ans);
        }
        return 0;
    }
  • 相关阅读:
    扩展中国剩余定理学习笔记
    寻找宝藏
    卢卡斯定理学习笔记
    [国家集训]矩阵乘法
    中国剩余定理学习笔记
    [CTSC2018]混合果汁
    数据结构(C语言版)第二章2.82.11 动态链表
    数据结构(C语言版)第二章2.12.7
    C语言中换行符和回车符的区别(转)
    C的xml编程libxml2(转摘)
  • 原文地址:https://www.cnblogs.com/Zinn/p/8969820.html
Copyright © 2011-2022 走看看