[9018_1963][IOI_1998]Picture

题目描述

N(N<5000) 张矩形的海报,照片和其他同样形状的图片贴在墙上。它们的边都是垂直的或水平的。每个矩形可以部分或者全部覆盖其他矩形。所有的矩形组成的集合的轮廓称为周长。写一个程序计算周长。

所有矩形的顶点坐标均为整数。所有的坐标都在 [-10000,10000] 的范围内,并且任何一个矩形面积都为整数。结果的值可能需要 32 位有符号整数表示。

输入

第1行: N,张贴在墙上的矩形的数目。 第 2..N+1行 接下来的N行中,每行都有两个点的坐标,分别是矩形的左下角坐标和右上角坐标。每一个坐标由 X 坐标和 Y 坐标组成。

输出

只有一行,为一个非负整数,表示输入数据中所有矩形集合的轮廓长度。

样例输入

7
-15 0 5 10
-5 8 20 25
15 -4 24 14
0 -6 16 4
2 15 10 22
30 10 36 20
34 0 40 16

样例输出

228


题解:

线段树+扫描线

对于每条线段,分横竖考虑,排序,坐标第一关键字,左右第2关键字

对于矩形左边线段,先统计这条线段区域0的个数,在把线段树中这条线段覆盖的区域+1,右边反过来

一定要记得右端点-1(因为题目给的是点,实际上是区间)

例如1,3。其实只覆盖2个区间(1,2;2,3)

#include<iostream> 
#include<cstdio> 
#include<cstring> 
#include<algorithm> 
using namespace std; 
struct data1{ 
    int l,r,k,p; 
}x[10001],y[10001]; 
struct data2{ 
    int x,s,l,r,la; 
}tree[80001]; 
int n; 
bool cmp(data1 a,data1 b) 
{ 
    if(a.k==b.k)return a.p>b.p; 
    return a.k<b.k; 
} 
void down(int x) 
{ 
    tree[x*2].x+=tree[x].la; 
    tree[x*2].la+=tree[x].la; 
    tree[x*2+1].x+=tree[x].la; 
    tree[x*2+1].la+=tree[x].la; 
    tree[x].la=0; 
} 
void up(int x) 
{ 
    tree[x].x=min(tree[x*2].x,tree[x*2+1].x); 
    if(tree[x*2].x==tree[x*2+1].x)tree[x].s=tree[x*2].s+tree[x*2+1].s; 
    if(tree[x*2].x<tree[x*2+1].x)tree[x].s=tree[x*2].s; 
    if(tree[x*2].x>tree[x*2+1].x)tree[x].s=tree[x*2+1].s; 
} 
void init(int x,int l,int r) 
{ 
    tree[x].l=l;tree[x].r=r;tree[x].la=0;tree[x].x=0; 
    if(l==r){tree[x].s=1;return;} 
    init(x*2,l,(l+r)/2);init(x*2+1,(l+r)/2+1,r); 
    up(x); 
} 
void add(int x,int l,int r,int k) 
{ 
    if(tree[x].l==l&&tree[x].r==r){tree[x].x+=k;tree[x].la+=k;return;} 
    down(x); 
    int mid=(tree[x].l+tree[x].r)/2; 
    if(r<=mid)add(x*2,l,r,k); 
    else if(l>mid)add(x*2+1,l,r,k); 
    else {add(x*2,l,mid,k);add(x*2+1,mid+1,r,k);} 
    up(x); 
} 
void query(int x,int l,int r,int &ansx,int &anss) 
{ 
    if(tree[x].l==l&&tree[x].r==r) 
    { 
        if(ansx==tree[x].x)anss+=tree[x].s; 
        if(tree[x].x<ansx)anss=tree[x].s; 
        ansx=min(ansx,tree[x].x);return; 
    } 
    down(x); 
    int mid=(tree[x].l+tree[x].r)/2; 
    if(r<=mid)query(x*2,l,r,ansx,anss); 
    else if(l>mid)query(x*2+1,l,r,ansx,anss); 
    else {query(x*2,l,mid,ansx,anss);query(x*2+1,mid+1,r,ansx,anss);} 
} 
int main() 
{ 
    scanf("%d",&n); 
    for(int i=1;i<=n;i++) 
    { 
        int _x1,_y1,_x2,_y2; 
        scanf("%d%d%d%d",&_x1,&_y1,&_x2,&_y2); 
        _x1+=10000;_x2+=10000;_y1+=10000;_y2+=10000; 
        y[i*2-1].l=_x1;y[i*2-1].r=_x2-1;y[i*2-1].k=_y1;y[i*2-1].p=1; 
        y[i*2].l=_x1;y[i*2].r=_x2-1;y[i*2].k=_y2;y[i*2].p=-1; 
        x[i*2-1].l=_y1;x[i*2-1].r=_y2-1;x[i*2-1].k=_x1;x[i*2-1].p=1; 
        x[i*2].l=_y1;x[i*2].r=_y2-1;x[i*2].k=_x2;x[i*2].p=-1; 
    } 
    n*=2;int ans=0; 
    sort(x+1,x+n+1,cmp);sort(y+1,y+n+1,cmp); 
    init(1,0,20000); 
    for(int i=1;i<=n;i++) 
    { 
        if(x[i].p==-1)add(1,x[i].l,x[i].r,-1); 
        int anss=0,ansx=999999999;query(1,x[i].l,x[i].r,ansx,anss); 
        if(x[i].p==1)add(1,x[i].l,x[i].r,1); 
        if(ansx==0)ans+=anss; 
    } 
    init(1,0,20000); 
    for(int i=1;i<=n;i++) 
    { 
        if(y[i].p==-1)add(1,y[i].l,y[i].r,-1); 
        int anss=0,ansx=999999999;query(1,y[i].l,y[i].r,ansx,anss); 
        if(y[i].p==1)add(1,y[i].l,y[i].r,1); 
        if(ansx==0)ans+=anss; 
    } 
    cout<<ans;return 0; 
}  

 

posted @ 2017-03-12 20:36  lher  阅读(212)  评论(0编辑  收藏  举报