bzoj1645 / P2061 [USACO07OPEN]城市的地平线City Horizon(扫描线)
P2061 [USACO07OPEN]城市的地平线City Horizon
扫描线
扫描线简化版
流程(本题为例):
把一个矩形用两条线段(底端点的坐标,向上长度,添加$or$删除)表示,按横坐标排序
$upd:$本题的底端点坐标简化为$(x,0)$
蓝后对纵坐标建一棵线段树(本题需要对高度进行离散化)。
每次对线段树进行覆盖$or$删除区间操作,顺便统计一下$k=$有多少点被覆盖到
而两次(线段)操作之间的长度为$r=x_{i}-x_{i-1}$
于是两条线段之间被覆盖的面积即为$k*r$
(某退役选手又一次省出了宝贵的1.5h)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 #define N 40010 7 struct line{ 8 int l,h,f;// l:横坐标 h:向上高度 f:添加/删除 9 line(){} 10 line(int A,int B,int C): 11 l(A),h(B),f(C){} 12 bool operator < (const line &tmp) const{ 13 return l<tmp.l; 14 } 15 }a[N<<1]; 16 int x[N],n,cnt,tn,sum[N<<2],tag[N<<2],res; 17 long long ans; 18 #define lc o<<1 19 #define rc o<<1|1 20 #define mid l+((r-l)>>1) 21 void upd(int o,int l,int r,line e){ 22 if(l>=r) return; //左端点在本题中简化成0,下同 23 if(x[r]<=e.h) tag[o]+=e.f;//覆盖层数增加/减少 24 else{ 25 upd(lc,l,mid,e); 26 if(e.h>x[mid]) upd(rc,mid,r,e);//注意mid~mid+1的区间不可被忽略 27 }sum[o]= tag[o]? x[r]-x[l]:sum[lc]+sum[rc];//是否被完全覆盖 28 } 29 int main(){ 30 scanf("%d",&n); int q1,q2,q3; 31 for(int i=1;i<=n;++i){ 32 scanf("%d%d%d",&q1,&q2,&q3); 33 a[++cnt]=line(q1,q3,1); 34 a[++cnt]=line(q2,q3,-1);//一个矩形用两条线段表示 35 x[i+1]=q3;//存横坐标用于离散化 36 }sort(a+1,a+cnt+1);//(线段)操作按横坐标排序 37 sort(x+1,x+n+2);x[0]=-1;//注意要加上坐标(0,0) 38 for(int i=1;i<=n+1;++i) 39 if(x[i]!=x[i-1]) x[++tn]=x[i];//离散化 40 upd(1,1,tn,a[1]); 41 for(int i=2;i<=cnt;++i){ 42 ans+=1ll*sum[1]*(a[i].l-a[i-1].l);//累计两条线段间的面积 43 upd(1,1,tn,a[i]); 44 }printf("%lld",ans); 45 return 0; 46 }