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 }
View Code
原文地址:https://www.cnblogs.com/kafuuchino/p/10023529.html