0%

扫描线

原题链接:Luogu P5490

扫描线求面积

离散化version

线段树中闭区间\([l, r]\)表示数轴上\([dot[l], dot[r+1]]\)的线段,这样子可以使得\(l==r\)时候,表示的区间不是一个点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <bits/stdc++.h>

using namespace std;

#define LL long long

const int MAXN=1e5+2;
const int INF=0x7fffffff;

struct line_t{
int l,r,h,mark;
bool operator<(const line_t& o)const{
return h<o.h;
}
};

vector<line_t> line;

vector<int> dot;

int n;

int find(int orix){
return lower_bound(dot.begin(),dot.end(),orix)-dot.begin();
}

#define ls (p<<1)
#define rs (p<<1|1)
#define MID int m=s+((t-s)>>1)

struct node_t{
int l,r,sum;
LL len;
}d[MAXN<<4];

void build(int p,int s,int t){
d[p].l=s,d[p].r=t;
d[p].len=0;
d[p].sum=0;
if(s==t)return;
MID;
build(ls,s,m);
build(rs,m+1,t);
}

void pushup(int p){
int l=d[p].l,r=d[p].r;
if(d[p].sum){
d[p].len=dot[r+1]-dot[l];
}else d[p].len=d[ls].len+d[rs].len;
}

void modify(int p,LL L,LL R,int c){
int l=d[p].l,r=d[p].r;
if(dot[r+1]<=L||dot[l]>=R)return;
if(L<=dot[l]&&dot[r+1]<=R){
d[p].sum+=c;
pushup(p);
return;
}
modify(ls,L,R,c);
modify(rs,L,R,c);
pushup(p);
}

int main(){
cin>>n;
for(int i=1,x,y,_x,_y;i<=n;++i){
cin>>x>>y>>_x>>_y;
line.push_back({x,_x,y,1});
line.push_back({x,_x,_y,-1});
dot.push_back(x);
dot.push_back(_x);
}
//discrete
dot.push_back(-INF);
sort(dot.begin(),dot.end());
dot.erase(unique(dot.begin(),dot.end()),dot.end());

//sort line
sort(line.begin(),line.end());

build(1,1,dot.size()-2);
LL ans=0;

for(int i=0;i<line.size()-1;++i){
modify(1,line[i].l,line[i].r,line[i].mark);
ans+=d[1].len*(line[i+1].h-line[i].h);
}

cout<<ans<<'\n';

return 0;
}

动态开点version

线段树中闭区间\([l, r]\)表示的实际数轴上\([l, r+1]\)的线段,数轴上每一个小区间\([x, x+1]\)表示线段树的数组中下标为\(x\)的叶子节点

示意图
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <bits/stdc++.h>
#define LL long long
using namespace std;

const int MAXN=1e5+2;
const int INF=0x7fffffff;

struct line_t{
int l,r,h,mark;

line_t(int _l,int _r,int _h,int _mark):l(_l),r(_r),h(_h),mark(_mark){}

bool operator<(const line_t& o)const{
return h<o.h;
}
};

vector<line_t> lines;

int n,cnt,rt;

#define ls d[p].lson
#define rs d[p].rson
#define MID int m=s+((t-s)>>1)

struct node_t{
int lson,rson,tag;
int len;
}d[MAXN<<7];

void pushup(int p,int s,int t){
if(d[p].tag){
d[p].len=t-s+1;
}else d[p].len=d[ls].len+d[rs].len;
}

void modify(int& p,int s,int t,int l,int r,int c){
if(!p)p=++cnt;
if(l<=s&&t<=r){
d[p].tag+=c;
pushup(p,s,t);
return;
}
MID;
if(l<=m)modify(ls,s,m,l,r,c);
if(r>m)modify(rs,m+1,t,l,r,c);
pushup(p,s,t);
}

int main(){
cin>>n;
for(int i=1,x,y,_x,_y;i<=n;++i){
cin>>x>>y>>_x>>_y;
lines.emplace_back(x,_x,y,1);
lines.emplace_back(x,_x,_y,-1);
}
sort(lines.begin(),lines.end());

LL ans=0;

for(int i=0;i<lines.size()-1;++i){
modify(rt,0,INF,lines[i].l,lines[i].r-1,lines[i].mark);
ans+=1ll*d[1].len*(lines[i+1].h-lines[i].h);
}cout<<ans<<'\n';
return 0;
}

扫描线求周长

原题链接POJ1177

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>

#define LL long long
using namespace std;

const int MAXN=5e3+2;
const int INF=0x7fffffff;

struct line_t{
int l,r,h,mark;

line_t(int _l,int _r,int _h,int _mark):l(_l),r(_r),h(_h),mark(_mark){}

bool operator<(const line_t& o)const{
if(h==o.h)return mark>o.mark;
return h<o.h;
}
};

vector<line_t> lines;

int n,cnt,rt;

#define ls d[p].lson
#define rs d[p].rson
#define MID int m=1ll*s+((1ll*t-s)>>1)

struct node_t{
int lson,rson,tag;//左儿子,右儿子,区间是否被线段完全覆盖
int c;// 区间线段个数
bool lc,rc;//区间左右端点是否被覆盖
int len;//区间内的线段总长度
}d[MAXN<<7];

void pushup(int p,int s,int t){
if(d[p].tag){
d[p].len=t-s+1;
d[p].lc=d[p].rc=true;
d[p].c=1;
}else{
d[p].len=d[ls].len+d[rs].len;
d[p].lc=d[ls].lc,d[p].rc=d[rs].rc;
d[p].c=d[ls].c+d[rs].c;
if(d[ls].rc&&d[rs].lc){
d[p].c-=1;
}
}
}

void modify(int& p,int s,int t,int l,int r,int c){
if(!p)p=++cnt;
if(l<=s&&t<=r){
d[p].tag+=c;
pushup(p,s,t);
return;
}
MID;
if(l<=m)modify(ls,s,m,l,r,c);
if(r>m)modify(rs,m+1,t,l,r,c);
pushup(p,s,t);
}

int main(){
cin>>n;
for(int i=1,x,y,_x,_y;i<=n;++i){
cin>>x>>y>>_x>>_y;
// lines.emplace_back(x,_x,y,1);
// lines.emplace_back(x,_x,_y,-1);
lines.push_back({x,_x,y,1});
lines.push_back({x,_x,_y,-1});
}
sort(lines.begin(),lines.end());

LL ans=0;
int pre=0;

for(int i=0;i<lines.size()-1;++i){
modify(rt,-INF,INF,lines[i].l,lines[i].r-1,lines[i].mark);
ans+=abs(d[1].len-pre);
ans+=2*d[1].c*(lines[i+1].h-lines[i].h);
pre=d[1].len;
}

ans+=lines.back().r-lines.back().l;

cout<<ans<<'\n';
return 0;
}