线段树--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 }