您的位置:首页 > 理论基础 > 计算机网络

http://acm.hdu.edu.cn/showproblem.php?pid=1255 扫描线 + 线段树 +离散化

2010-08-20 15:20 387 查看
]/*
*  这个跟昨天写的矩形面积的并是差不多的,而且我译开始还是写的一样的,sample都相差那么一点的
*  看了别人的加了moresum就OK那里的更新还是有点不理解的,转下一下的供自己回忆
题意:求矩形的交的面积!覆盖两次或以上!
将每个矩形的两条纵向边看成两个事件点,遇到左端点,插入该纵向边,遇到右节点,删除该边!
对所有y坐标进行离散化!进行线段树的插入和更新操作!
其实这道题跟求矩形的并的面积类似。不同的是更新每个节点覆盖长度的操作!
我采用cover,once,more这三个变量来维护线段树。
cover:表示该节点被覆盖多少次。
once:表示该节点表示的长度中,被覆盖1次以上的长度。
more:表示该节点表示的长度中,被覆盖2次以上的长度。
插入操作:找到属于当前边范围的节点,cover+=v。v是个标志,表示是插入边或删除边。
更新操作比较复杂。
当前节点被覆盖两次或以上,那么该点的once和more值都是节点表示的长度。
当前节点被覆盖一次,那么once等于节点的长度,而more等于左右子树被覆盖一次以上的长度的和。
当节点没有被覆盖,那么once等于左右子树的once值的和,more等于左右子树more的值的和。 http://hi.baidu.com/ccbow/blog/item/b1d17a139ae9e329dc54014d.html */
#include <iostream>
#include <cstdio>
#include <algorithm>
#define LL(x) ((x) << 1)
#define RR(x) ((x) << 1 | 1)
using namespace std;
const int N = 1555;
struct Seg_tree{
int l, r;
int st;
double sum;
double moresum; // 加了一个这个就AC了
int mid(){
return (l + r) >> 1;
}
}tree[6 * N];
struct Line{
double high;
double l, r;
int st;
}line[2 * N];
double pos[2 * N];
int len;
inline bool cmp(const Line &a, const Line &b){
return a.high < b.high;
}
inline void Build(int l ,int r, int node){
tree[node].l = l;
tree[node].r = r;
tree[node].st = 0;
tree[node].sum= 0;
tree[node].moresum = 0;
if(l == r)
return;
int mid = (l + r) >> 1;
Build(l, mid, LL(node));
Build(mid + 1, r, RR(node));
}
inline void Update(int node){
if(tree[node].st ){
tree[node].sum = pos[tree[node].r + 1] - pos[tree[node].l];
} else if(tree[node].l == tree[node].r){
tree[node].sum = 0;
} else{
tree[node].sum = tree[LL(node)].sum + tree[RR(node)].sum;
}
if(tree[node].st > 1){ // 加了一个moresum
tree[node].moresum = pos[tree[node].r + 1] - pos[tree[node].l];
} else if(tree[node].l == tree[node].r){
tree[node].moresum = 0;
}else if(tree[node].st > 0){
tree[node].moresum = tree[LL(node)].sum + tree[RR(node)].sum;
}else{
tree[node].moresum = tree[LL(node)].moresum + tree[RR(node)].moresum;
}
}
inline void Update(int l, int r, int node, int st){
if(l <= tree[node].l && tree[node].r <= r){
tree[node].st += st;
Update(node);
return ;
}
int mid = tree[node].mid();
if(r <= mid){
Update(l, r, LL(node), st);
} else if(l > mid){
Update(l, r, RR(node), st);
} else{
Update(l, mid, LL(node), st);
Update(mid + 1, r, RR(node), st);
}
Update(node);
}
inline int Bin(double x){
int low = 0;
int high = len - 1;
//puts("Bin");
while(low <= high){
int mid = (low + high) >> 1;
if(pos[mid] == x)
return mid;
if(pos[mid] < x){
low = mid + 1;
} else{
high = mid - 1;
}
}
return -1;
}
int main(){
int t;
scanf("%d", &t);
while(t--){
int n;
scanf("%d", &n);
double x1, y1, x2, y2;
int m = 0;
for(int i = 0; i < n; i++){
scanf("%lf %lf %lf %lf", &x1, &y1, &x2, &y2);
line[m].high = y1;		line[m].st = 1;
line[m + 1].high = y2;  line[m + 1].st = -1;
pos[m] = line[m].l = line[m + 1].l = x1;
pos[m + 1] = line[m].r = line[m + 1].r = x2;
m += 2;
}
sort(line, line + m, cmp);
sort(pos, pos + m);
//printf("m :: %d/n", m);
len = 0;
for(int i = 0; i < m; i++){
if(i == 0 || pos[i - 1] != pos[i])
pos[len++] = pos[i];
}
Build(0, len - 1, 1);
//printf("len :: %d/n", len);
double ans = 0;
for(int i = 0; i < m - 1; i++){
int l = Bin(line[i].l);
int r = Bin(line[i].r) - 1;
//printf("l :: %d r :: %d/n", l, r);
Update(l, r, 1, line[i].st);
ans += tree[1].moresum * (line[i + 1].high - line[i].high);
}
printf("%0.2lf/n", ans); // 早Eclipse 下C++ ans + 0.001 才能4舍5入的
}
}
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  tree build struct eclipse c