线段树--P5490 【模板】扫描线

应该是九月份最后一篇了,这段时间比较高产,国庆勉强能休2天,不用写国庆作业是我不敢想象的快乐(⊙v⊙),楼下书桌里卷子能有1.5cm,肉眼可见的知识的厚度

回归正题,扫描线和正常线段树的差别就在于我维护的是什么,我怎么维护

扫描线和它的名字一样,一条平行于x轴的直线,从下往上扫过n个矩形,划分成多个区域,如图:

求矩形的面积,我们需要知道长和高,而线段长可以转化成坐标差,所以X数组可以用来记录坐标,举个栗子:

我们还知道每次都一定是先经过一个矩形的下底再经过一个上底,所以把上底附为-1,下底附为1,记录一下高度,矩形的高就可以表示为上一个扫面线的高度减下一个扫描线的高度,线段树维护一下矩形的长和下底的长度就可以了,记得把X数组进行排序

pushup函数:如果我碰到了一个下底,更新的矩形长为右坐标减左坐标,否则为左儿子的长加右儿子的长

1 void pushup(int k,ll l,ll r){
2   if (tree[k].sum){tree[k].len=x[r+1]-x[l];return;}
3   tree[k].len=tree[ls(k)].len+tree[rs(k)].len;
4 }

update函数:如果是下底,那么sum就有了值,代表扫描线网上的地方需要计算面积,如果是上底,那么sum不一定没有值,只是减少,代表它对应的矩形面积计算完毕

1 void update(int k,ll l,ll r,ll nl,ll nr,int val){
2   if(x[r+1]<=nl||nr<=x[l]) return;
3   if (nl<=x[l]&&x[r+1]<=nr){tree[k].sum+=val;pushup(k,l,r);return;}
4   int mid=(l+r)>>1;
5   update(ls(k),l,mid,nl,nr,val);
6   update(rs(k),mid+1,r,nl,nr,val);
7   pushup(k,l,r);
8 }

完整代码,感觉自己讲的不太好,但是代码写的应该还是挺清楚的:

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstdio>
 4 #include <cstring>
 5 #define ll long long
 6 #define ls(x) (x<<1)
 7 #define rs(x) (x<<1|1)
 8 using namespace std;
 9 const int maxn=4e5+10;
10 ll n,xx1,xx2,yy1,yy2,ans;
11 struct node{
12   ll l,r,h;
13   int val;
14 }line[maxn*4];
15 bool operator < (const node &x,const node &y){
16   return x.h<y.h;
17 }
18 struct ask{
19   int sum;
20   ll len;
21 }tree[maxn*4];
22 ll x[2*maxn];
23 void pushup(int k,ll l,ll r){
24   if (tree[k].sum){tree[k].len=x[r+1]-x[l];return;}
25   tree[k].len=tree[ls(k)].len+tree[rs(k)].len;
26 }
27 void update(int k,ll l,ll r,ll nl,ll nr,int val){
28   if(x[r+1]<=nl||nr<=x[l]) return;
29   if (nl<=x[l]&&x[r+1]<=nr){tree[k].sum+=val;pushup(k,l,r);return;}
30   int mid=(l+r)>>1;
31   update(ls(k),l,mid,nl,nr,val);
32   update(rs(k),mid+1,r,nl,nr,val);
33   pushup(k,l,r);
34 }
35 int main(){
36     scanf ("%lld",&n);
37     for(int i = 1;i <= n;i++){
38       scanf("%lld%lld%lld%lld",&xx1,&yy1,&xx2,&yy2);
39       x[2*i-1]=xx1,x[2*i]=xx2;
40       line[2*i-1]=(node){xx1,xx2,yy1,1};
41       line[2*i]=(node){xx1,xx2,yy2,-1};
42     }
43     n<<=1;
44     sort(line+1,line+n+1);
45     sort(x+1,x+n+1);
46     int cnt=unique(x+1,x+n+1)-x-1;
47     for (int i = 1;i < n;i++){
48       update(1,1,cnt-1,line[i].l,line[i].r,line[i].val);
49       ans+=tree[1].len*(line[i+1].h-line[i].h);
50     }
51     printf("%lld\n",ans);
52   return 0;
53 }

 

posted @ 2020-09-30 08:47  小又又  阅读(131)  评论(0编辑  收藏  举报