[POJ1389]Area of Simple Polygons(扫描线+线段树)

70 篇文章 0 订阅
13 篇文章 0 订阅

题目描述

传送门

题解

经典的扫描线问题,过程中线段树辅助。
先按照横坐标排序,然后从左到右扫,如果是矩形的左端就将这个线段+1,如果是矩形的右端就将这个线段-1,不断更新答案。
注意可能有很多次覆盖,所以查询的时候不应该直接查询sum,而应该是区间内有几个点被覆盖了。

UPD-2017.4.19:上面那个时间复杂度好不科学啊…(捂脸
移步:http://blog.csdn.net/clove_unique/article/details/70242872

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

const int max_n=1005;
const int max_tree=3e5+5;

int x1,y1,x2,y2,cnt,n,ans;
int sum[max_tree],delta[max_tree];
struct hp{int x,y1,y2,f;}a[max_n];

inline int cmp(hp a,hp b){return a.x<b.x||a.x==b.x&&a.f>b.f;}
inline bool get(int x){return x;}
inline void update(int now){
    sum[now]=sum[now<<1]+sum[now<<1|1];
}
inline void pushdown(int now,int l,int r,int mid){
    if (delta[now]!=0){
        sum[now<<1]+=delta[now]*(mid-l+1);
        delta[now<<1]+=delta[now];
        sum[now<<1|1]+=delta[now]*(r-mid);
        delta[now<<1|1]+=delta[now];
        delta[now]=0;
    }
}
inline void interval_change(int now,int l,int r,int lrange,int rrange,int v){
    int mid=(l+r)>>1;
    if (lrange<=l&&r<=rrange){
        sum[now]+=v*(r-l+1);
        delta[now]+=v;
        return;
    }
    pushdown(now,l,r,mid);
    if (lrange<=mid) interval_change(now<<1,l,mid,lrange,rrange,v);
    if (mid+1<=rrange) interval_change(now<<1|1,mid+1,r,lrange,rrange,v);
    update(now);
}
inline int query(int now,int l,int r,int lrange,int rrange){
    int mid=(l+r)>>1,ans=0;
    if (l==r) return get(sum[now]); 
    pushdown(now,l,r,mid);
    if (lrange<=mid) ans+=query(now<<1,l,mid,lrange,rrange);
    if (mid+1<=rrange) ans+=query(now<<1|1,mid+1,r,lrange,rrange);
    return ans;
}

int main(){
    while (~scanf("%d%d%d%d",&x1,&y1,&x2,&y2)){
        if (x1==-1&&y1==-1&&x2==-1&&y2==-1) return 0;
        cnt=n=ans=0;
        memset(sum,0,sizeof(sum));
        memset(delta,0,sizeof(delta));

        cnt=0; n=0;
        if (!(x1==x2||y1==y2)){
            a[++cnt].x=x1,a[cnt].y1=y1+1,a[cnt].y2=y2,a[cnt].f=1;
            a[++cnt].x=x2,a[cnt].y1=y1+1,a[cnt].y2=y2,a[cnt].f=-1;
            n=max(n,y1+1); n=max(n,y2);
        }
        while (~scanf("%d%d%d%d",&x1,&y1,&x2,&y2)){
            if (x1==-1&&y1==-1&&x2==-1&&y2==-1) break; if (x1==x2||y1==y2) continue;
            n=max(n,y1+1); n=max(n,y2);
            a[++cnt].x=x1,a[cnt].y1=y1+1,a[cnt].y2=y2,a[cnt].f=1;
            a[++cnt].x=x2,a[cnt].y1=y1+1,a[cnt].y2=y2,a[cnt].f=-1;
        }
        sort(a+1,a+cnt+1,cmp);

        interval_change(1,1,n,a[1].y1,a[1].y2,a[1].f);
        for (int i=2;i<=cnt;++i){
            ans+=query(1,1,n,1,n)*(a[i].x-a[i-1].x);
            interval_change(1,1,n,a[i].y1,a[i].y2,a[i].f);
        }
        printf("%d\n",ans);
    }
}

总结

不要再手残脑残数据范围了。
本来能1A的题T_T

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值