【线段树+扫描线】HDU 1542+1255

【线段树+扫描线】
简单的说就是从下到上扫描线段,累加记录该线段添加进去之后在总区间的映射有效长度*高度差。


线段树扫描线详解:矩形面积的并:http://www.cnblogs.com/scau20110726/archive/2013/04/12/3016765.html

矩形面积的交:http://www.cnblogs.com/scau20110726/archive/2013/04/14/3020998.html

看了这两篇博客+代码才有所理解。因为扫描的是线段,在线段树中分界点那部分区间可能无法表示,然后就变成了区间左闭右开[l,r),在更新的时候我们可以只更新闭区间即[l,r-1],在记录结果的时候把那个在加上。自己动手画图模拟会有更深的理解。


注意数据的离散化。。。

col[root]枚举到当前边的时候,下方有多少有用线段。(该区间矩形的下边比上边多几条)

即当前结点区间的覆盖情况,不必向下更新,当遇到矩形的上边的时候,直接更新当前结点。
sum[root]区间被覆盖的长度

summ[root]区间被重复覆盖的长度/*注意更新*/


HDU 1542 【矩形面积的并】CODE:

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<stack>
#include<math.h>
#include<map>
#include<iostream>
#define INF 0x3f3f3f3f
#define lson l,m,root<<1
#define rson m+1,r,root<<1|1
typedef  long long LL;
using namespace std;
const int mod=998244353;
const int maxn=5005;
double sum[maxn<<2],X[maxn<<2];
int col[maxn<<2];
struct node
{
    double l,r,h;
    int s;
    node() {};
    node(double a,double b,double c,int d)
    {
        l=a,r=b,h=c;
        s=d;
    }
    bool operator <(const node &cmp)const
    {
        return h<cmp.h;
    }
}ss[maxn<<2];
void pushup(int l,int r,int root)
{
    if(col[root])
        sum[root]=X[r+1]-X[l];//*********
    else if(l==r)
        sum[root]=0;
    else
        sum[root]=sum[root<<1]+sum[root<<1|1];
}
void update(int L,int R,int c,int l,int r,int root)
{
    if(L<=l&&r<=R)
    {
        col[root]+=c;
        pushup(l,r,root);
        return;
    }
    int m=(l+r)>>1;
    if(L<=m)
        update(L,R,c,lson);
    if(R>m)
        update(L,R,c,rson);
    pushup(l,r,root);
}
int main()
{
   int n,T=0;
   while(~scanf("%d",&n)&&n)
   {
       int m=0,k=1;
       double a,b,c,d;
       for(int i=0;i<n;i++)
       {
           scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
           X[m]=a;
           ss[m++]=node(a,c,b,1);
           X[m]=c;
           ss[m++]=node(a,c,d,-1);
       }
       sort(X,X+m);
       sort(ss,ss+m);
       for(int i=1;i<m;i++)
       {
           if(X[i]!=X[i-1])
            X[k++]=X[i];
       }
       double ans=0;
       memset(col,0,sizeof(col));
       memset(sum,0,sizeof(sum));
       for(int i=0;i<m-1;i++)
       {
           int l=lower_bound(X,X+k,ss[i].l)-X;
           int r=lower_bound(X,X+k,ss[i].r)-X-1;//******
           if(l<=r)
            update(l,r,ss[i].s,0,k-1,1);
           ans+=sum[1]*(ss[i+1].h-ss[i].h);
       }
       printf("Test case #%d\nTotal explored area: %.2lf\n\n",++T,ans);//注意格式
   }
}


HDU 1225【矩形面积的交】 CODE:

summ[]数组的更新:1、col[root]>1,即该区间全部被覆盖了两次及两次以上,长度就是该区间的长度;

                                 2、l==r最底层的叶子节点,无论覆盖没覆盖,都为0;

                                 3、col[root]=1,左右子节点覆盖一次及一次以上的和(因为col[]没有向下更新,如果子区间有被                                 覆盖的,则就是被重复覆盖的);

                                 4、其他,左右子节点覆盖两次及两次以上的和。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<stack>
#include<math.h>
#include<map>
#include<iostream>
#define INF 0x3f3f3f3f
#define lson l,m,root<<1
#define rson m+1,r,root<<1|1
typedef  long long LL;
using namespace std;
const int mod=998244353;
const int maxn=5005;
double sum[maxn<<2],X[maxn<<2];
double summ[maxn<<2];
int col[maxn<<2];
struct node
{
    double l,r,h;
    int s;
    node() {};
    node(double a,double b,double c,int d)
    {
        l=a,r=b,h=c;
        s=d;
    }
    bool operator <(const node &cmp)const
    {
        return h<cmp.h;
    }
} ss[maxn<<2];
void pushup(int l,int r,int root)
{
    if(col[root])
        sum[root]=X[r+1]-X[l];
    else if(l==r)
        sum[root]=0;
    else
        sum[root]=sum[root<<1]+sum[root<<1|1];
    if(col[root]>1)
        summ[root]=X[r+1]-X[l];
    else if(l==r)
        summ[root]=0;
    else if(col[root]==1)
        summ[root]=sum[root<<1]+sum[root<<1|1];
    else
        summ[root]=summ[root<<1]+summ[root<<1|1];
}
void update(int L,int R,int c,int l,int r,int root)
{
    if(L<=l&&r<=R)
    {
        col[root]+=c;
        pushup(l,r,root);
        return;
    }
    int m=(l+r)>>1;
    if(L<=m)
        update(L,R,c,lson);
    if(R>m)
        update(L,R,c,rson);
    pushup(l,r,root);
}
int main()
{
    int n,t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        int m=0,k=1;
        double a,b,c,d;
        for(int i=0; i<n; i++)
        {
            scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
            X[m]=a;
            ss[m++]=node(a,c,b,1);
            X[m]=c;
            ss[m++]=node(a,c,d,-1);
        }
        sort(X,X+m);
        sort(ss,ss+m);
        for(int i=1; i<m; i++)
        {
            if(X[i]!=X[i-1])
                X[k++]=X[i];
        }
        double ans=0;
        memset(col,0,sizeof(col));
        memset(sum,0,sizeof(sum));
        memset(summ,0,sizeof(summ));
        for(int i=0; i<m-1; i++)
        {
            int l=lower_bound(X,X+k,ss[i].l)-X;
            int r=lower_bound(X,X+k,ss[i].r)-X-1;
            if(l<=r)
                update(l,r,ss[i].s,0,k-1,1);
           // cout<<l<<" "<<r<<"---"<<sum[1]<<endl;
            ans+=summ[1]*(ss[i+1].h-ss[i].h);
        }
        printf("%.2lf\n",ans);
    }
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值