题目大意:给若干个矩形,求轮廓边长。
题目分析:与求面积类似。按从下往上扫描,仍然是底边添加,上边删除。但要同时维护竖边的数目,每次扫描对答案的贡献为扫描线上总覆盖长度的变化量加上竖边的增量。总覆盖长度的变化为正说明下轮廓增加,为负以为着碰到了上轮廓增加。
代码如下:
# include<bits/stdc++.h> using namespace std; # define mid (l+(r-l)/2) # define LL long long const int N=5000; struct Segment { int x1,x2,y; int d; }; struct Node { int cnt; ///覆盖的竖线数目 int len; ///被覆盖总长度 int time; ///被覆盖覆盖的次数 bool cl,cr; ///左右端点是否被覆盖 }; Segment seg[N<<1]; Node nde[(N<<4)+5]; bool comp(Segment &s1,Segment &s2) { return s1.y<s2.y; } void build(int rt,int l,int r) { nde[rt].cnt=0; nde[rt].len=0; nde[rt].time=0; nde[rt].cl=nde[rt].cr=false; if(l==r) return ; build(rt<<1,l,mid); build(rt<<1|1,mid+1,r); } void pushUp(int rt,int l,int r) { if(nde[rt].time>0){ nde[rt].cl=nde[rt].cr=true; nde[rt].cnt=2; nde[rt].len=r-l+1; }else if(l==r){ nde[rt].cl=nde[rt].cr=false; nde[rt].cnt=0; nde[rt].len=0; }else{ nde[rt].cl=nde[rt<<1].cl; nde[rt].cr=nde[rt<<1|1].cr; nde[rt].len=nde[rt<<1].len+nde[rt<<1|1].len; nde[rt].cnt=nde[rt<<1].cnt+nde[rt<<1|1].cnt; if(nde[rt<<1].cr&&nde[rt<<1|1].cl) nde[rt].cnt-=2; } } void update(int rt,int l,int r,int L,int R,int d) { if(L<=l&&r<=R){ nde[rt].time+=d; pushUp(rt,l,r); }else{ if(L<=mid) update(rt<<1,l,mid,L,R,d); if(R>mid) update(rt<<1|1,mid+1,r,L,R,d); pushUp(rt,l,r); } } int main() { int n; while(~scanf("%d",&n)) { int L=10000,R=-10000; int x1,y1,x2,y2; for(int i=0;i<n;++i){ scanf("%d%d%d%d",&x1,&y1,&x2,&y2); seg[i<<1].x1=seg[i<<1|1].x1=x1,seg[i<<1].y=y1; seg[i<<1].x2=seg[i<<1|1].x2=x2,seg[i<<1|1].y=y2; seg[i<<1].d=1; seg[i<<1|1].d=-1; L=min(x1,L); R=max(x2,R); } n<<=1; build(1,L,R-1); sort(seg,seg+n,comp); int ans=0; int last=0; seg[n].y=seg[n-1].y; for(int i=0;i<n;++i){ update(1,L,R-1,seg[i].x1,seg[i].x2-1,seg[i].d); ans+=nde[1].cnt*(seg[i+1].y-seg[i].y); ans+=abs(nde[1].len-last); last=nde[1].len; } printf("%d ",ans); } return 0; }