Time Limit: | | Memory Limit: |
Total Submissions: | | Accepted: |
Description
Input
The input file is terminated by a line containing a single 0. Don't process it.
Output
Output a blank line after each test case.
Sample Input
2 10 10 20 20 15 15 25 25.5 0
Sample Output
Test case #1 Total explored area: 180.00
【题意】:
线段树经典应用,求矩形并的面积
【分析】:
第一道矩形几何题,主要是练习线段树来的
求矩形的并,由于矩形的位置可以多变,因此矩形的面积一下子不好求
这个时候,可以采用“分割”的思想,即把整块的矩形面积分割成几个小矩形的面积,然后求和就行了
这里我们可以这样做,把每个矩形投影到 y 坐标轴上来
然后我们可以枚举矩形的 x 坐标,然后检测当前相邻 x 坐标上 y 方向的合法长度,两种相乘就是面积
然后关键就是如何用线段树来维护那个 “合法长度”
可以这样来搞
线段树的节点这样定义
struct node { int left,right,cov; double len; }
cov 表示当前节点区间是否被覆盖,len 是当前区间的合法长度
然后我们通过“扫描线”的方法来进行扫描
枚举 x 的竖边,矩形的左边那条竖边就是入边,右边那条就是出边了
然后把所有这些竖边按照 x 坐标递增排序,每次进行插入操作
由于坐标不一定为整数,因此需要进行离散化处理
每次插入时如果当前区间被完全覆盖,那么就要对 cov 域进行更新
入边 +1 出边 -1
更新完毕后判断当前节点的 cov 域是否大于 0
如果大于 0,那么当前节点的 len 域就是节点所覆盖的区间
否则
如果是叶子节点,则 len=0
如果内部节点,则 len=左右儿子的 len 之和
----------------以上转自http://hi.baidu.com/legend_ni/blog/item/106e9f8a34ff9b04b21bba71
Problem: | | User: | |||||||
Memory: | | Time: | |||||||
Language: | | Result: | |||||||
Accepted | 0MS | 268K | C++ | ||||||
| | | | | | | | | |
#include<iostream>
#include<algorithm>
#include<math.h>
using namespace std;
const int maxn = 201; //离散化后,最多200个不同的值
double bin[maxn]; //离散化后存有有序且唯一的关键字的数组
int N;
//seg tree
struct seg
{
int a,b;
double len;
int cov;
};
seg tree[maxn*4];
void maketree(int a,int b,int k)
{
tree[k].a = a;
tree[k].b = b;
tree[k].len = 0;
tree[k].cov = 0;
if(a+1 == b)
return;
int mid = (a+b)>>1;
maketree(a,mid,k<<1);
maketree(mid,b,k<<1|1);
}
inline void update_info(int k)
{
if(tree[k].cov == 0)
tree[k].len = tree[k<<1].len + tree[k<<1|1].len;
}
void update(int c,int d,char flag,int k)
{
if(c <= tree[k].a && tree[k].b <= d)
{
if(flag == 1) //insert
{
tree[k].cov++;
tree[k].len = bin[tree[k].b] - bin[tree[k].a];
}
else //del
{
tree[k].cov --;
if(tree[k].cov == 0)
{
if(tree[k].a +1 == tree[k].b) //叶结点
tree[k].len = 0;
else
tree[k].len = tree[k<<1].len + tree[k<<1|1].len;
}
}
return;
}
if(c < tree[k<<1].b)
update(c,d,flag,k<<1);
if(d > tree[k<<1|1].a)
update(c,d,flag,k<<1|1);
update_info(k);
}
//垂直线
struct VLine
{
double x;
int y1,y2;
char flag; // 1:入边 -1: 出边
};
bool cmp(VLine vl1,VLine vl2)
{
return vl1.x < vl2.x;
}
VLine VL[maxn];
int tail;
double X1[maxn],X2[maxn],Y1[maxn],Y2[maxn];
void Add(double x1,int y1,double x2,int y2)
{
if(x1 == x2 || y1 == y2) //判断是不是一条线或点
return;
VL[tail].x = x1;
VL[tail].y1 = y1;
VL[tail].y2 = y2;
VL[tail].flag = 1;
tail++;
VL[tail].x = x2;
VL[tail].y1 = y1;
VL[tail].y2 = y2;
VL[tail].flag = -1;
tail++;
}
///
int size;
double tmp[maxn];
void decritize()
{
for(int i=0; i<N; i++)
{
tmp[i*2] = Y1[i];
tmp[i*2+1] = Y2[i];
}
sort(tmp,tmp+2*N);
size = 1;
bin[1] = tmp[0];
for(int i=1; i<2*N; i++) //离散化为1..size
{
if(tmp[i] != bin[size]) // 要保证bin里的是互不相同的
bin[++size] = tmp[i];
}
}
inline int Binary(double a[],int l,int r,double x) //二分查找x,并返回为序号 O(logN)
{
int mid;
while(l<=r) //这里少了个=,害自己调试半天..要记住..
{
mid = (l+r)>>1;
if(x < a[mid])
r = mid -1;
else
if(x > a[mid])
l = mid +1;
else
return mid;
}
}
void input()
{
tail = 0;
for(int i = 0; i<N; i++)
scanf("%lf%lf%lf%lf",&X1[i],&Y1[i],&X2[i],&Y2[i]);
decritize();
for(int i=0; i<N; i++)
Add( X1[i], Binary(bin,1,size,Y1[i]), X2[i], Binary(bin,1,size,Y2[i]) ); //注意加入的矩形是Y轴离散化后的矩形
}
int main()
{
int T = 0;
while(scanf("%d",&N) && N)
{
input();
maketree(1,size,1);
sort(VL,VL+tail,cmp);
double area = 0;
update(VL[0].y1,VL[0].y2,VL[0].flag ,1);
for(int i=1; i<tail; i++) //扫描线
{
area += (VL[i].x - VL[i-1].x) * tree[1].len;
update(VL[i].y1,VL[i].y2,VL[i].flag ,1);
}
printf("Test case #%dnTotal explored area: %.2lfnn",++T,area);
}
return 0;
}
这里update一下自己的代码
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#define maxn 210
using namespace std;
const double eps = 1e-5;
int n;
struct opt{
double x, a, b;
int tp;
int l, r;
opt(double x_ = 0, double a_ = 0, double b_ = 0, int tp_ = 0, int l_ = 0, int r_ = 0){
x = x_;
a = a_;
b = b_;
tp = tp_;
l = l_;
r = r_;
}
}q[maxn << 2];
bool cmp(const opt& a, const opt& b){
return a.x < b.x;
}
int amt;
double h[maxn << 2];
int cnt;
struct Node{
int vis;
double len, cov;
void clear(){vis = len = cov = 0;}
}t[maxn << 2];
#define lc id << 1
#define rc id << 1 | 1
void pushup(int id){if(t[id].vis == 0)t[id].cov = t[lc].cov + t[rc].cov;}
void build(int id, int l, int r){
t[id].clear();
if(l == r){
if(l != 1)t[id].len = h[l] - h[l-1];
else t[id].len = 0;
return;
}
int mid = l + r >> 1;
build(lc, l, mid);
build(rc, mid+1, r);
t[id].len = t[lc].len + t[rc].len;
}
void update(int id, int l, int r, int L, int R, int val){
if(L == l && R == r){
if(val == 1){
t[id].vis ++;
t[id].cov = t[id].len;
}
else{
t[id].vis --;
if(t[id].vis == 0){
if(l == r)t[id].cov = 0;
else pushup(id);
}
}
return;
}
int mid = l + r >> 1;
if(R <= mid)update(lc, l, mid, L, R, val);
else if(L > mid)update(rc, mid+1, r, L, R, val);
else update(lc, l, mid, L, mid, val), update(rc, mid+1, r, mid+1, R, val);
pushup(id);
}
int main(){
int Case = 0;
while(scanf("%d", &n) && n){
double a, b, c, d;
cnt = amt = 0;
for(int i = 1; i <= n; i ++){
scanf("%lf%lf%lf%lf", &a, &b, &c, &d);
h[++ cnt] = b, h[++ cnt] = d;
q[++ amt] = opt(a, b, d, 1);
q[++ amt] = opt(c, b, d, -1);
}
sort(h + 1, h + 1 + cnt);
cnt = unique(h + 1, h + 1 + cnt) - h - 1;
for(int i = 1; i <= amt; i ++){
q[i].l = lower_bound(h + 1, h + 1 + cnt, q[i].a) - h;
q[i].r = lower_bound(h + 1, h + 1 + cnt, q[i].b) - h;
}
sort(q + 1, q + 1 + amt, cmp);
build(1, 1, cnt);
double ans = 0;
for(int i = 1; i <= amt; i ++){
ans += t[1].cov * (q[i].x - q[i-1].x);
update(1, 1, cnt, q[i].l+1, q[i].r, q[i].tp);
}
printf("Test case #%d\nTotal explored area: %.2f\n", ++ Case, ans);
puts("");
}
return 0;
}