1. 程式人生 > >bzoj1645 / P2061 [USACO07OPEN]城市的地平線City Horizon(掃描線)

bzoj1645 / P2061 [USACO07OPEN]城市的地平線City Horizon(掃描線)

line 覆蓋 problem define city n) mes 一次 面積

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 }
View Code

bzoj1645 / P2061 [USACO07OPEN]城市的地平線City Horizon(掃描線)