扫描线是一种用来处理矩形相交的面积问题的算法
渐近时间复杂度约为O(nlogn) O(nlogn)O(nlogn)
参考博客:https://blog.csdn.net/niiick/article/details/81985889
练习题目(POJ - 1151 Atlantis)
题目链接:http://poj.org/problem?id=1151
扫描线能将一个二维的转成一维的然后就行求解;我们在区间上进行求解len的时候可以用线段树维护这样能将时间复杂度降到
nlogn
#include <iostream>
#include <map>
#include <set>
#include <vector>
#include <algorithm>
#include <iomanip>
#define gcd __gcd
#define endl '\n'
using namespace std;
typedef long long ll;
typedef long double ld;
const ll maxn = 1e5 + 7;
const ll mod = 1e9 + 7;
ll n;
struct tnode
{
ll l,r,add;
ld len;
}t[maxn << 2];
struct node
{
ld x,y1,y2;
ll k;
}a[maxn];
bool cmp(node a,node b)
{
return a.x < b.x;
}
set<ld>s;
vector<ld>cov;
map<ld,ll>rak;
void bulid(ll p,ll l,ll r)
{
t[p].l = l,t[p].r = r,t[p].add = 0,t[p].len = 0.0;
if(l == r)return ;
ll mid = (l + r) / 2;
bulid(p * 2,l,mid);
bulid(p * 2 + 1,mid + 1,r);
}
void spread(ll p)
{
if(t[p].add > 0)
{
t[p].len = cov[t[p].r + 1] - cov[t[p].l];
}
else
{
t[p].len = t[p * 2].len + t[p * 2 + 1].len;
}
}
void update(ll p,ll l,ll r,ll d)
{
if(t[p].l >= l && t[p].r <= r)
{
t[p].add += d;
spread(p);
return ;
}
ll mid = (t[p].l + t[p].r) / 2;
if(mid >= l)update(p * 2,l,r,d);
if(r > mid)update(p * 2 + 1,l,r,d);
spread(p);
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
ll ts = 0;
while(cin >> n && n)
{
cov.clear(),s.clear(),rak.clear();
ld x1,x2,y1,y2;
ll w = 0;
for(int i = 1; i <= n; i ++)
{
cin >> x1 >> y1 >> x2 >> y2;
a[++w].x = x1,a[w].y1 = y1,a[w].y2 = y2,a[w].k = 1;
a[++w].x = x2,a[w].y1 = y1,a[w].y2 = y2,a[w].k = -1;
s.insert(y1),s.insert(y2);
}
sort(a + 1,a + 1 + w,cmp);
cov.push_back(0.0);
ll m = 0;
set<ld>::iterator it;
for(it = s.begin(); it != s.end(); it ++)
{
cov.push_back(*it);
rak[*it] = (++m);
}
bulid(1,1,m - 1);
ld be = 0;
ld ans = 0;
for(int i = 1; i <= w; i ++)
{
ans += (a[i].x - be) * t[1].len;
update(1,rak[a[i].y1],rak[a[i].y2] - 1,a[i].k);
be = a[i].x;
}
cout << "Test case #" << (++ ts) << endl;
cout << "Total explored area: " << fixed << setprecision(2) << ans << endl << endl;
}
return 0;
}
多个矩形的面积交
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1255
#include <bits/stdc++.h>
#define gcd __gcd
#define endl '\n'
using namespace std;
typedef long long ll;
typedef double ld;
const ll maxn = 1e6 + 7;
const ll mod = 1e9 + 7;
ll n;
struct tnode
{
ll l,r,add;
ld len,len1;
}t[maxn << 2];
struct node
{
ld x,y1,y2;
ll k;
}a[maxn];
bool cmp(node a,node b)
{
return a.x < b.x;
}
set<ld>s;
vector<ld>cov;
unordered_map<ld,ll>rak;
void bulid(ll p,ll l,ll r)
{
t[p].l = l,t[p].r = r,t[p].add = 0,t[p].len = t[p].len1 = 0.0;
if(l == r)return ;
ll mid = (l + r) / 2;
bulid(p * 2,l,mid);
bulid(p * 2 + 1,mid + 1,r);
}
void spread(ll p)
{
if(t[p].add == 1)
{
t[p].len = cov[t[p].r + 1] - cov[t[p].l];
t[p].len1 = t[p * 2].len + t[p * 2 + 1].len;
}
else if(t[p].add >= 2)
{
t[p].len = t[p].len1 = cov[t[p].r + 1] - cov[t[p].l];
}
else
{
t[p].len = t[p * 2].len + t[p * 2 + 1].len;
t[p].len1 = t[p * 2].len1 + t[p * 2 + 1].len1;
}
}
void update(ll p,ll l,ll r,ll d)
{
if(t[p].l >= l && t[p].r <= r)
{
t[p].add += d;
spread(p);
return ;
}
ll mid = (t[p].l + t[p].r) / 2;
if(mid >= l)update(p * 2,l,r,d);
if(r > mid)update(p * 2 + 1,l,r,d);
spread(p);
}
int main()
{
//ios::sync_with_stdio(0);
//cin.tie(0),cout.tie(0);
ll ts = 0;
ll z,n;
cin >> z;
while(z--)
{
cin >> n;
cov.clear(),s.clear(),rak.clear();
ld x1,x2,y1,y2;
ll w = 0;
for(int i = 1; i <= n; i ++)
{
cin >> x1 >> y1 >> x2 >> y2;
a[++w].x = x1,a[w].y1 = y1,a[w].y2 = y2,a[w].k = 1;
a[++w].x = x2,a[w].y1 = y1,a[w].y2 = y2,a[w].k = -1;
s.insert(y1),s.insert(y2);
}
sort(a + 1,a + 1 + w,cmp);
cov.push_back(0.0);
ll m = 0;
set<ld>::iterator it;
for(it = s.begin(); it != s.end(); it ++)
{
cov.push_back(*it);
rak[*it] = (++m);
}
bulid(1,1,m - 1);
ld be = 0;
ld ans = 0;
for(int i = 1; i <= w; i ++)
{
ans += (a[i].x - be) * t[1].len1;
update(1,rak[a[i].y1],rak[a[i].y2] - 1,a[i].k);
be = a[i].x;
}
printf("%.2lf\n", ans);//我认你做大哥
//cout << fixed << setprecision(2) << ans << endl;精度竟然不够
}
return 0;
}
poj2482
题目链接:http://poj.org/problem?id=2482
#include <iostream>
#include <map>
#include <set>
#include <vector>
#include <algorithm>
#include <iomanip>
#define gcd __gcd
#define endl '\n'
using namespace std;
typedef long long ll;
typedef double ld;
const ll maxn = 1e6 + 7;
const ll mod = 1e9 + 7;
ll n;
struct tnode
{
ll l,r,add,dat;
}t[maxn << 2];
struct node
{
ld x,y1,y2;
ll k;
}a[maxn];
bool cmp(node a,node b)
{
return a.x < b.x;
}
set<ld>s;
vector<ld>cov;
map<ld,ll>rak;
void bulid(ll p,ll l,ll r)
{
t[p].l = l,t[p].r = r,t[p].add = 0,t[p].dat = 0;
if(l == r)return ;
ll mid = (l + r) / 2;
bulid(p * 2,l,mid);
bulid(p * 2 + 1,mid + 1,r);
}
void spread(ll p)
{
if(t[p].add)
{
t[p * 2].dat += t[p].add;
t[p * 2 + 1].dat += t[p].add;
t[p * 2].add += t[p].add;
t[p * 2 + 1].add += t[p].add;
t[p].add = 0;
}
}
void update(ll p,ll l,ll r,ll d)
{
if(t[p].l >= l && t[p].r <= r)
{
t[p].add += d;
t[p].dat += d;
//spread(p);
return ;
}
spread(p);
ll mid = (t[p].l + t[p].r) / 2;
if(mid >= l)update(p * 2,l,r,d);
if(r > mid)update(p * 2 + 1,l,r,d);
t[p].dat = max(t[p * 2].dat,t[p * 2 + 1].dat);
}
int main()
{
//ios::sync_with_stdio(0);
//cin.tie(0),cout.tie(0);
ll ts = 0;
ll n,ww,h;
while(cin >> n >> ww >> h)
{
cov.clear(),s.clear(),rak.clear();
ll x,y,d;
ll w = 0;
for(int i = 1; i <= n; i ++)
{
cin >> x >> y >> d;
a[++w].x = x,a[w].y1 = y,a[w].y2 = y + h,a[w].k = d;
a[++w].x = x + ww,a[w].y1 = y,a[w].y2 = y + h,a[w].k = -d;
s.insert(a[w].y1);
s.insert(a[w].y2);
}
sort(a + 1,a + 1 + w,cmp);
cov.push_back(0.0);
ll m = 0;
set<ld>::iterator it;
for(it = s.begin(); it != s.end(); it ++)
{
cov.push_back(*it);
rak[*it] = (++m);
}
bulid(1,1,m - 1);
ll ans = -1e18;
for(int i = 1; i <= w; i ++)
{
update(1,rak[a[i].y1],rak[a[i].y2] - 1,a[i].k);
ans = max(ans,t[1].dat);
}
cout << ans << endl;
}
return 0;
}