线段树——讲课用——矩形并的周长

题目链接:http://poj.org/problem?id=1177

N<=5000个矩形 坐标范围[-10000,10000] ,均为整数 求矩形并的周长

对横着的和竖着的分别求一次
暴力算法:
对于每一条横边从左到右扫一遍,如果是矩形的下边,先判断当前坐标覆盖数为0,ans+,然后当前坐标覆盖数+1(覆盖数不为0也要加)
如果是矩形的上边,先判断当前坐标覆盖数为1,ans++,然后当前坐标覆盖数-1(覆盖数不为1也要减)
对于每一条竖边,同理(下边改成左边,上边改成右边)
注:1、边[l,r]的扫描范围为[l,r-1]
2、排序时,若几条横边的高度一样,上边优先。同理,竖边左边优先。
原因:这种情况下是一个矩形的下边和另一个矩形的上边重合,两条边的长度都不能算。
如果先扫下边,扫下边之前一定扫了上边,坐标覆盖可能为1,导致答案错误累加

线段树做法:
类似于求矩形并的面积
不同点:累加答案累加与上一次的差,不需要再乘高度
注:1、边[l,r]的扫描范围是[l,r-1]
2、排序时,若几条边高度一样,谁在前无所谓。因为累加与上一次的差

#include<cstdio>
#include<iostream>
#include<algorithm>

using namespace std;

#define delta 10001
#define N 20002

struct rectangle
{
    int x,l,r,f;
}tra[N],ver[N]; 

int sum[N<<2],col[N<<2];
int opl,opr,fl;

void read(int &x)
{
    x=0; int f=1; char c=getchar();
    while(!isdigit(c)) { if(c=='-') f=-1; c=getchar(); }
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } 
    x*=f; 
} 

bool cmp1(rectangle a,rectangle b)
{
    return a.x<b.x;
}

void up(int k,int l,int r)
{
    if(col[k]) sum[k]=r-l+1;
    else if(l==r) {sum[k]=0; return;}
    else sum[k]=sum[k<<1]+sum[k<<1|1];
}

void change(int k,int l,int r)
{
    if(l>=opl && r<=opr)
    {
        col[k]+=fl; 
        up(k,l,r);
        return;
    }
    int mid=l+r>>1;
    if(opl<=mid) change(k<<1,l,mid);
    if(opr>mid) change(k<<1|1,mid+1,r);
    up(k,l,r);
}

int main()
{
    int n;
    read(n);
    int x1,y1,x2,y2;
    int a,b;
    for(int i=1;i<=n;++i)
    {
        read(x1); read(y1); read(x2); read(y2); 
        x1+=delta; y1+=delta; x2+=delta; y2+=delta;
        a=i*2-1; b=i*2;
        tra[a].l=y1; tra[a].r=y2; 
        tra[a].x=x1; tra[a].f=1;
        tra[b].l=y1; tra[b].r=y2; 
        tra[b].x=x2; tra[b].f=-1; 
        ver[a].l=x1; ver[a].r=x2; 
        ver[a].x=y1; ver[a].f=1;
        ver[b].l=x1; ver[b].r=x2;
        ver[b].x=y2; ver[b].f=-1;
    }
    int m=n<<1; 
    sort(tra+1,tra+m+1,cmp1);
    int ans=0,last=0;
    for(int i=1;i<=m;++i)
    {
        opl=tra[i].l; opr=tra[i].r-1; fl=tra[i].f;
        change(1,1,N-1);
        ans+=abs(sum[1]-last);
        last=sum[1];
    }
    sort(ver+1,ver+m+1,cmp1);
    last=0;
    for(int i=1;i<=m;++i)
    {
        opl=ver[i].l; opr=ver[i].r-1; fl=ver[i].f;
        change(1,1,N-1);
        ans+=abs(sum[1]-last);
        last=sum[1];
    }
    printf("%d",ans);
}

 

posted @ 2019-07-06 21:09  TRTTG  阅读(274)  评论(0编辑  收藏  举报