C31 扫描线 P1856 [IOI1998] 矩形周长
视频链接:222 扫描线 矩形周长并_哔哩哔哩_bilibili
Luogu P1856 [IOI1998] [USACO5.5] 矩形周长
// 扫描线+线段树+离散化 35ms #include <iostream> #include <cstring> #include <algorithm> using namespace std; #define ls u<<1 #define rs u<<1|1 #define N 10005 struct line{ //扫描线 int l,r,y; int tag; //入边:+1, 出边:-1 bool operator<(line &t){ return y==t.y ? tag>t.tag : y<t.y; } //入边优先,两矩形相切等价于相交 }L[N]; struct tree{ //线段树 int l,r; int cnt,len; //区间覆盖次数和覆盖长度 int sum; //区间覆盖竖边条数 bool lcover,rcover;//左右端点是否被覆盖 }tr[N*8]; int X[N]; //X坐标 void build(int u,int l,int r){ //建树 tr[u].l=l, tr[u].r=r; if(l==r) return; int mid=(l+r)>>1; build(ls,l,mid); build(rs,mid+1,r); } void pushup(int u){ //上传 int l=tr[u].l,r=tr[u].r; if(tr[u].cnt){ tr[u].len=X[r+1]-X[l]; tr[u].sum=2; tr[u].lcover=tr[u].rcover=true; } else{ tr[u].len=tr[ls].len+tr[rs].len; tr[u].sum=tr[ls].sum+tr[rs].sum; tr[u].lcover=tr[ls].lcover; tr[u].rcover=tr[rs].rcover; if(tr[ls].rcover && tr[rs].lcover) tr[u].sum-=2; //左右区间连续 } } void change(int u,int l,int r,int tag){ //区修 if(l>tr[u].r || r<tr[u].l) return; if(l<=tr[u].l && tr[u].r<=r){ tr[u].cnt+=tag; pushup(u); return; } change(ls,l,r,tag); change(rs,l,r,tag); pushup(u); } int main(){ int n,x1,y1,x2,y2,last=0; scanf("%d",&n); for(int i=1; i<=n; i++){ scanf("%d%d%d%d",&x1,&y1,&x2,&y2); L[i]={x1,x2,y1,1}; L[n+i]={x1,x2,y2,-1}; X[i]=x1; X[n+i]=x2; } n*=2; sort(L+1,L+n+1); sort(X+1,X+n+1); int s=unique(X+1,X+n+1)-X-1; build(1,1,s-1); int res=0; for(int i=1; i<n; i++){ int l=lower_bound(X+1,X+s+1,L[i].l)-X; int r=lower_bound(X+1,X+s+1,L[i].r)-X; change(1,l,r-1,L[i].tag); res+=abs(tr[1].len-last); //横边 last=tr[1].len; res+=tr[1].sum*(L[i+1].y-L[i].y); //竖边 } res+=L[n].r-L[n].l; //最后一条扫描线 printf("%d\n",res); }
// 两扫描线+两线段树+离散化 47ms #include <iostream> #include <cstring> #include <algorithm> using namespace std; #define ls u<<1 #define rs u<<1|1 #define N 10005 struct line{ //扫描线 int l,r,h; int tag; //入边:+1, 出边:-1 bool operator<(line &t){ return h==t.h ? tag>t.tag : h<t.h; } //入边优先,两矩形相切等价于相交 }L1[N],L2[N]; struct tree{ //线段树 int l,r; int cnt,len; //区间覆盖次数和覆盖长度 }t1[N*8],t2[N*8]; int X[N],Y[N]; //X,Y坐标 void pushup(int u,tree *t,int *x){ if(t[u].cnt) t[u].len=x[t[u].r+1]-x[t[u].l]; else t[u].len=t[ls].len+t[rs].len; } void build(int u,int l,int r,tree *t){ //建树 t[u].l=l, t[u].r=r; if(l==r) return; int mid=(l+r)>>1; build(ls,l,mid,t); build(rs,mid+1,r,t); } void change(int u,int l,int r,int tag,tree *t,int *x){ //区修 if(l>t[u].r || r<t[u].l) return; if(l<=t[u].l && t[u].r<=r){ t[u].cnt+=tag; pushup(u,t,x); return; } change(ls,l,r,tag,t,x); change(rs,l,r,tag,t,x); pushup(u,t,x); } int main(){ int n,x1,y1,x2,y2,last1=0,last2=0; scanf("%d",&n); for(int i=1; i<=n; i++){ scanf("%d%d%d%d",&x1,&y1,&x2,&y2); L1[i]={x1,x2,y1,1}; L1[n+i]={x1,x2,y2,-1}; X[i]=x1; X[n+i]=x2; L2[i]={y1,y2,x1,1}; L2[n+i]={y1,y2,x2,-1}; Y[i]=y1; Y[n+i]=y2; } n*=2; sort(L1+1,L1+n+1); sort(L2+1,L2+n+1); sort(X+1,X+n+1); sort(Y+1,Y+n+1); int s1=unique(X+1,X+n+1)-X-1; int s2=unique(Y+1,Y+n+1)-Y-1; build(1,1,s1-1,t1); build(1,1,s2-1,t2); int res=0; for(int i=1; i<n; i++){ int l1=lower_bound(X+1,X+s1+1,L1[i].l)-X; int r1=lower_bound(X+1,X+s1+1,L1[i].r)-X; int l2=lower_bound(Y+1,Y+s2+1,L2[i].l)-Y; int r2=lower_bound(Y+1,Y+s2+1,L2[i].r)-Y; change(1,l1,r1-1,L1[i].tag,t1,X); change(1,l2,r2-1,L2[i].tag,t2,Y); res+=abs(t1[1].len-last1)+abs(t2[1].len-last2); last1=t1[1].len; last2=t2[1].len; } res+=L1[n].r-L1[n].l + L2[n].r-L2[n].l; printf("%d\n",res); return 0; }