[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; }