墙上贴着许多形状相同的海报、照片。它们的边都是水平和垂直的。每个矩形图片可能部分或全部的覆盖了其他图片。所有矩形合并后的边长称为周长。
所有矩形的边界。所有矩形顶点的坐标都是整数。
输入文件的第一行是一个整数N(0<=N<5000),表示有多少个矩形。接下来N行给出了每一个矩形左下角坐标和右上角坐标(所有坐标的数值范围都在-10000到10000之间)。
输出文件只有一个正整数,表示所有矩形的周长。
题解
线段树扫描线 https://www.luogu.org/problemnew/solution/P1856
维护的东西非常巧妙 注意覆盖标记不下传 因为只查询根节点
1 #include<cstdio> 2 #include<cstdlib> 3 #include<algorithm> 4 using namespace std; 5 const int N=10000+5; 6 int n; 7 struct edge{int x,y,h,c;}a[N]; 8 bool cmp(edge p,edge q) {return p.h<q.h || (p.h==q.h&& p.c>q.c);} 9 10 int tot,b[N]; 11 inline int hehe(int x) {return lower_bound(b+1,b+tot+1,x)-b;} 12 13 struct point{int l,r,cov,cnt,len; bool lf,rf; }t[4*N]; 14 inline void pushup(int i,int l,int r) 15 {if(t[i].cov) 16 {t[i].len=t[i].r-t[i].l; 17 t[i].lf=t[i].rf=1; 18 t[i].cnt=1; 19 } 20 else 21 {t[i].len=t[2*i].len+t[2*i+1].len; 22 t[i].lf=t[2*i].lf; t[i].rf=t[2*i+1].rf; 23 t[i].cnt=t[2*i].cnt+t[2*i+1].cnt; 24 if(t[2*i].rf && t[2*i+1].lf) t[i].cnt--; 25 } 26 } 27 void build(int i,int l,int r) 28 {t[i].l=b[l]; t[i].r=b[r+1]; 29 if(l==r) return; 30 int mid=l+r>>1; 31 build(2*i,l,mid); build(2*i+1,mid+1,r); 32 } 33 void change(int i,int l,int r,int p,int q,int v) 34 {if(p<=l && r<=q) {t[i].cov+=v; pushup(i,l,r); return;} 35 int mid=l+r>>1; 36 if(p<=mid) change(2*i, l, mid,p,q,v); 37 if(mid<q) change(2*i+1,mid+1,r,p,q,v); 38 pushup(i,l,r); 39 } 40 int main() 41 { 42 scanf("%d",&n); int x1,y1,x2,y2; 43 44 for(int i=1;i<=n;i++) 45 { scanf("%d%d%d%d",&x1,&y1,&x2,&y2); 46 a[2*i-1].x=a[2*i].x=x1; a[2*i-1].y=a[2*i].y=x2; 47 a[2*i-1].h=y1; a[2*i].h=y2; 48 a[2*i-1].c=1; a[2*i].c=-1; 49 b[++tot]=x1; b[++tot]=x2; 50 } 51 sort(a+1,a+2*n+1,cmp); 52 53 sort(b+1,b+tot+1); tot=unique(b+1,b+tot+1)-b-1; 54 55 build(1,1,tot-1); int ans=0,last=0; 56 57 for(int i=1;i<=2*n;i++) 58 { change(1,1,tot-1,hehe(a[i].x),hehe(a[i].y)-1,a[i].c); 59 60 ans+=2*t[1].cnt*(a[i+1].h-a[i].h)+abs(t[1].len-last); 61 last=t[1].len; 62 } 63 printf("%d\n",ans); 64 return 0; 65 }
原文地址:https://www.cnblogs.com/YuXiaoze/p/11420758.html
时间: 2024-10-11 22:36:54