扫描线:离散x坐标,排序y坐标,从下到上扫描每一个点所在的线
面积:每次扫描就更新底面的长度 ,每次增加的面积 == 高度差 * 底面长度
周长:除了更新地面长度外,还要更新左右端点是否被覆盖,每次增加的周长就是
上下两次底面长度的差值绝对值 + 未被覆盖的左右端点个数乘高度差
更新:左闭右开 【l,r)
poj 1177 题目链接
求周长
#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
using namespace std;
const int N = 5555 * 4; /// [-10000,10000] 区间长度为2e4
const int INF = 0x3f3f3f3f;
struct node{
int x,y,h,f;
bool operator < (const node &p) const{
return h < p.h;
}
node() {}
node(int a,int b,int c,int d):x(a),y(b),h(c),f(d){}
}s[N];
int tree[N << 2],lazy[N << 2],num[N << 2],lr[N << 2],rr[N << 2];
void push_up(int l,int r,int id)
{
if (lazy[id]){
tree[id] = r - l + 1;
num[id] = 1;
lr[id] = rr[id] = 1;
}
else if (l == r){
tree[id] = 0;
num[id] = 0;
lr[id] = rr[id] = 0;
}
else {
tree[id] = tree[id << 1] + tree[id << 1 | 1];
num[id] = num[id << 1] + num[id << 1 | 1] - (lr[id << 1 | 1] & rr[id << 1]);
lr[id] = lr[id << 1];
rr[id] = rr[id << 1 | 1];
}
}
void build(int l,int r,int id)
{
tree[id] = num[id] = lazy[id] = lr[id] = rr[id] = 0;
if (l != r){
int mid = (l + r) >> 1;
build(l,mid,id << 1);
build(mid + 1,r,id << 1 | 1);
}
}
void update(int a,int b,int flag,int l,int r,int id)
{
if (a <= l && r <= b){
lazy[id] += flag;
push_up(l,r,id);
return ;
}
int mid = (l + r) >> 1;
if (a <= mid) update(a,b,flag,l,mid,id << 1);
if (b > mid) update(a,b,flag,mid + 1,r,id << 1 | 1);
push_up(l,r,id);
}
int main()
{
int n;
while(scanf("%d",&n) == 1){
int cnt = 0;
int mi = INF,mx = -INF;
for (int i = 0; i < n; i++){
int x3,x4,y3,y4;
scanf("%d %d %d %d",&x3,&y3,&x4,&y4);
x3 += 11000;
x4 += 11000;
y3 += 11000;
y4 += 11000;
s[cnt++] = node(x3,x4,y3,1);
s[cnt++] = node(x3,x4,y4,-1);
mi = min(mi,min(x3,x4));
mx = max(mx,max(x3,x4));
}
build(mi,mx - 1,1);
sort(s,s + cnt);
int ans = 0,pre = 0;
for (int i = 0; i < cnt; i++){
update(s[i].x,s[i].y - 1,s[i].f,mi,mx - 1,1);
// cout << s[i].x << " " << s[i].y << " " << s[i].f << " " << mi << " " << mx << endl;
ans += (s[i + 1].h - s[i].h) * (2 * num[1]);
ans += abs(tree[1] - pre);
pre = tree[1];
}
cout << ans << endl;
}
return 0;
}
hdu 1542 题目链接
求覆盖的面积
#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
using namespace std;
const int N = 444;
const int INF = 0x3f3f3f3f;
struct node{
double l,r,h;
int f;
node(){}
node(double a,double b,double c,int d):l(a),r(b),h(c),f(d){}
bool operator < (const node &p) const{
return h < p.h;
}
}s[N];
int lazy[N << 2];
double X[N << 2],tree[N << 2];
void push_up(int id,int l,int r)
{
if (lazy[id]){
tree[id] = X[r + 1] - X[l];
}
else if (l == r) {
tree[id] = 0;
}
else {
tree[id] = tree[id << 1] + tree[id << 1 | 1];
}
}
void update(int flag,int a,int b,int l,int r,int id)
{
if (a <= l && r <= b){
lazy[id] += flag;
push_up(id,l,r);
return ;
}
int mid = (l + r) >> 1;
if (a <= mid) update(flag,a,b,l,mid,id << 1);
if (b > mid) update(flag,a,b,mid + 1,r,id << 1 | 1);
push_up(id,l,r);
}
int main()
{
int n,Case = 1;
while(scanf("%d",&n) == 1 && n){
int cnt = 0;
for (int i = 0; i < n; i++){
double x3,y3,x4,y4;
scanf("%lf %lf %lf %lf",&x3,&y3,&x4,&y4);
s[cnt] = node(x3,x4,y3,1);
X[cnt++] = x3;
s[cnt] = node(x3,x4,y4,-1);
X[cnt++] = x4;
}
sort(s,s + cnt);
sort(X,X + cnt);
int len = unique(X,X + cnt) - X;
double ans = 0;
for (int i = 0; i < cnt; i++){
int a = lower_bound(X,X + len,s[i].l) - X;
int b = lower_bound(X,X + len,s[i].r) - X - 1;
update(s[i].f,a,b,0,len - 1,1);
// cout << "a = " << a << " b = " << b << " " << tree2[0] << endl;
ans += (s[i + 1].h - s[i].h) * tree[1];
}
printf("Test case #%d\nTotal explored area: %.2f\n",Case++,ans);
cout << endl;
}
return 0;
}
hdu 1255 题目链接
hdu1542 升级版,覆盖两次的面积
离散化x坐标,更新区间为左闭右开
计算时就 X[(r + 1)] - x[l]
#include <bits/stdc++.h>
using namespace std;
const int N = 2e4 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 10007;
typedef long long ll;
struct node{
double l,r,h;
int flag;
node(){}
node(double a,double b,double c,int d):l(a),r(b),h(c),flag(d){}
bool operator < (const node &p) const{
return h < p.h;
}
}s[N];
int lazy[N << 2];
double X[N << 2],tree[N << 2],tree2[N << 2];
void push_up(int id,int l,int r)
{
/// 因为更新区间时r - 1了,所以现在要加1回去
if (lazy[id] >= 2){
tree2[id] = X[r + 1] - X[l];
}
else if (lazy[id] == 1){
tree2[id] = tree[id << 1] + tree[id << 1 | 1];
tree[id] = X[r + 1] - X[l];
}
else {
tree2[id] = tree2[id << 1] + tree2[id << 1 | 1];
tree[id] = tree[id << 1] + tree[id << 1 | 1];
}
}
void update(int flag,int a,int b,int l,int r,int id)
{
if (a <= l && r <= b){
lazy[id] += flag;
push_up(id,l,r);
return ;
}
int mid = (l + r) >> 1;
if (a <= mid) update(flag,a,b,l,mid,id << 1);
if (b > mid) update(flag,a,b,mid + 1,r,id << 1 | 1);
push_up(id,l,r);
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
int n;
scanf("%d",&n);
int cnt = 0;
for (int i = 0; i < n; i++){
double x3,y3,x4,y4;
scanf("%lf %lf %lf %lf",&x3,&y3,&x4,&y4);
s[cnt] = node(x3,x4,y3,1);
X[cnt++] = x3;
s[cnt] = node(x3,x4,y4,-1);
X[cnt++] = x4;
}
sort(s,s + cnt);
sort(X,X + cnt);
int len = unique(X,X + cnt) - X;
double ans = 0;
for (int i = 0; i < cnt; i++){
int a = lower_bound(X,X + len,s[i].l) - X;
int b = lower_bound(X,X + len,s[i].r) - X - 1;
update(s[i].flag,a,b,0,len - 1,1);
// cout << "a = " << a << " b = " << b << " " << tree2[0] << endl;
ans += (s[i + 1].h - s[i].h) * tree2[1];
}
printf("%.2f\n",ans);
}
return 0;
}
hdu 3642 题目链接
三维扫描
按Z排序成每一层,然后每一层都进行一次扫描线的面积计算,得到的面积乘上高度差就是那一层的结果
初始化的时候需要扫到下一层,因为下一层会影响到更新(push_up的时候没有特判 l==r 这种情况)
当然,直接四个memset初始化也可以
#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 2222;
const int INF = 0x3f3f3f3f;
typedef long long ll;
struct node{
int l,r,h,f;
node(){}
node(int a,int b,int c,int d):l(a),r(b),h(c),f(d){}
bool operator < (const node &p) const{
return h < p.h;
}
}s[N];
struct Point{
int x3,x4,y3,y4,z3,z4;
void init() {cin >> x3 >> y3 >> z3 >> x4 >> y4 >> z4;}
}p[N];
int lazy[N << 2],tree[N << 2],tree2[N << 2],tree3[N << 2];
int X[N << 2],Z[N << 2];
void push_up(int l,int r,int id)
{
if (lazy[id] >= 3){
tree3[id] = X[r + 1] - X[l];
}
else if (lazy[id] == 2){
tree3[id] = tree[id << 1] + tree[id << 1 | 1];
tree2[id] = X[r + 1] - X[l];
}
else if (lazy[id] == 1){
tree3[id] = tree2[id << 1] + tree2[id << 1 | 1];
tree2[id] = tree[id << 1] + tree[id << 1 | 1];
tree[id] = X[r + 1] - X[l];
}
else {
tree3[id] = tree3[id << 1] + tree3[id << 1 | 1];
tree2[id] = tree2[id << 1] + tree2[id << 1 | 1];
tree[id] = tree[id << 1] + tree[id << 1 | 1];
}
}
void build(int l,int r,int id)
{
tree[id << 1] = tree2[id << 1] = tree3[id << 1] = lazy[id << 1] = 0;
tree[id << 1 | 1] = tree2[id << 1 | 1] = tree3[id << 1 | 1] = lazy[id << 1 | 1] = 0;
if (l != r){
int mid = (l + r) >> 1;
build(l,mid,id << 1);
build(mid + 1,r,id << 1 | 1);
}
}
void update(int flag,int a,int b,int l,int r,int id)
{
if (a <= l && r <= b){
// cout << "lazyid = " << lazy[id] << " id = " << id << endl;
lazy[id] += flag;
push_up(l,r,id);
return ;
}
int mid = (l + r) >> 1;
if (a <= mid) update(flag,a,b,l,mid,id << 1);
if (b > mid) update(flag,a,b,mid + 1,r,id << 1 | 1);
push_up(l,r,id);
}
int main()
{
int t,Case = 1;
scanf("%d",&t);
while(t--){
int n;
scanf("%d",&n);
int cnt = 0;
for (int i = 0; i < n; i++){
p[i].init();
Z[cnt++] = p[i].z3;
Z[cnt++] = p[i].z4;
}
if (n < 3){
printf("Case %d: 0\n",Case++);
continue;
}
sort(Z,Z + cnt);
cnt = unique(Z,Z + cnt) - Z;
ll ans = 0;
for (int i = 0; i < cnt - 1; i++){
int k = 0;
for (int j = 0; j < n; j++){
if (p[j].z3 <= Z[i] && Z[i] < p[j].z4){
X[k] = p[j].x3;
s[k++] = node(p[j].x3,p[j].x4,p[j].y3,1);
X[k] = p[j].x4;
s[k++] = node(p[j].x3,p[j].x4,p[j].y4,-1);
}
}
sort(X,X + k);
sort(s,s + k);
int len = unique(X,X + k) - X;
//memset(tree,0,sizeof(tree));
// memset(tree2,0,sizeof(tree2));
// memset(tree3,0,sizeof(tree3));
// memset(lazy,0,sizeof(lazy));
build(0,len - 1,1);
ll res = 0;
for (int j = 0; j < k - 1; j++){
int a = lower_bound(X,X + len,s[j].l) - X;
int b = lower_bound(X,X + len,s[j].r) - X - 1;
update(s[j].f,a,b,0,len - 1,1);
res += 1ll * tree3[1] * (s[j + 1].h - s[j].h);
// cout << "i = " << i << " a = " << a << " b = " << b << " len - 1= " << len - 1 << " res = " << res << " tree3[1] = " << tree3[1] << endl;
}
ans += res * (Z[i + 1] - Z[i]);
}
printf("Case %d: %I64d\n",Case++,ans);
}
return 0;
}