转自:http://www.cppblog.com/abilitytao/archive/2010/07/21/120927.html
参考:http://www.cnblogs.com/Booble/archive/2010/10/10/1847163.html扫描线的描述
题目大意:给出一组矩阵,要你求出重叠矩阵的的总周长
解题思路:线段树,离散化,跟上题求矩阵的面积类似,不同的是还要求出横向覆盖的线段总长度
比较笨的办法是按照上题那样的方法,先求出纵向覆盖的线段总长度然后再求出横向覆盖的线段总长度,然后相加,这样超时。。。。
比较好的办法是在求纵向y覆盖的线段的同时,求出这个纵向线段所覆盖覆盖了横向x的几个线段,即求出纵向y方向的线段被横向x方向的线段切割成了几段,
切割的段数*2就是,这个区域横向覆盖的线段总长,在求切割了几段,要区分出,y方向的线段连续不连续
连续的为左图,第2个纵向覆盖了1个横向线段,即被纵向切割成一个线段,不连续的为右图,第2个纵向覆盖了2个横向线段,即被纵向切割成2个线段
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 5001;
struct node
{
int l, r;
int len;
int seg;
int cover;
int sum;
bool lcover, rcover;
node()
{
lcover = rcover = false;
l = r = len = seg = cover = 0;
}
};
struct line
{
int y1, y2, x;
bool inout;
bool operator <(const line &b) const
{
return x < b.x;
}
};
int n, cnt, ans, index[2 * maxn];
line lines[2 * maxn];
node nodes[4 * maxn];
void build(int l, int r, int dex);
void insert(int l, int r, int dex);
void del(int l, int r, int dex);
void getLen(int nu);
void getSeg(int nu);
int getIndex(int x);
int main()
{
freopen("slyar.in", "r", stdin);
freopen("slyar.out", "w", stdout);
scanf("%d", &n);
cnt = 0;
for(int i = 0; i < n; i++)
{
int x1, x2, y1, y2;
scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
lines[i * 2].x = x1;
lines[i * 2 + 1].x = x2;
lines[i * 2].y1 = lines[i * 2 + 1].y1 = y1;
lines[i * 2].y2 = lines[i * 2 + 1].y2 = y2;
lines[i * 2].inout = true;
lines[i * 2 + 1].inout = false;
index[i * 2] = y1;
index[i * 2 + 1] = y2;
}
sort(lines, lines + 2 * n);
sort(index, index + 2 * n);
for(int i = 1; i < 2 * n; i++)
{
if(index[i] != index[i - 1])
index[cnt++] = index[i-1];
}
index[cnt++] = index[2 * n - 1];
build(0, cnt - 1, 1);
ans = 0;
int lsum = 0;
for(int i = 0; i < 2 * n - 1; i++)
{
if(lines[i].inout)
insert(getIndex(lines[i].y1), getIndex(lines[i].y2), 1);
else
del(getIndex(lines[i].y1), getIndex(lines[i].y2), 1);
ans += abs(nodes[1].sum - lsum);
lsum = nodes[1].sum;
ans += nodes[1].seg * (lines[i+1].x - lines[i].x) * 2;
}
del(getIndex(lines[2 * n - 1].y1), getIndex(lines[2 * n - 1].y2), 1);
ans += abs(nodes[1].sum - lsum);
printf("%d\n", ans);
fclose(stdin);
fclose(stdout);
return 0;
}
int getIndex(int x)
{
return lower_bound(index, index + cnt, x) - index;
}
void build(int l, int r, int dex)
{
nodes[dex].l = l;
nodes[dex].r = r;
nodes[dex].lcover = nodes[dex].rcover = false;
nodes[dex].cover = nodes[dex].seg = nodes[dex].sum = 0;
nodes[dex].len = index[r] - index[l];
if(r - l > 1)
{
int mid = (r + l) >> 1;
build(l, mid, 2 * dex);
build(mid, r, 2 * dex + 1);
}
}
void insert(int l, int r, int dex)
{
if(nodes[dex].l == l && nodes[dex].r == r)
nodes[dex].cover++;
else
{
int mid = (nodes[dex].r + nodes[dex].l) >> 1;
if(r <= mid)
insert(l, r, 2 * dex);
else if(l >= mid)
insert(l, r, 2 * dex + 1);
else
{
insert(l, mid, 2 * dex);
insert(mid, r, 2 * dex + 1);
}
}
getLen(dex);
getSeg(dex);
}
void del(int l, int r, int dex)
{
if(nodes[dex].l == l && nodes[dex].r == r)
nodes[dex].cover--;
else
{
int mid = (nodes[dex].r + nodes[dex].l) >> 1;
if(r <= mid)
del(l, r, 2 * dex);
else if(l >= mid)
del(l, r, 2 * dex + 1);
else
{
del(l, mid, 2 * dex);
del(mid, r, 2 * dex + 1);
}
}
getLen(dex);
getSeg(dex);
}
void getLen(int nu)
{
if(nodes[nu].cover > 0)
nodes[nu].sum = nodes[nu].len;
else if(nodes[nu].r - nodes[nu].l > 1)
nodes[nu].sum = nodes[2 * nu].sum + nodes[2 * nu + 1].sum;
else
nodes[nu].sum = 0;
}
void getSeg(int nu)
{
if(nodes[nu].cover > 0)
{
nodes[nu].lcover = nodes[nu].rcover = true;
nodes[nu].seg = 1;
}
else if(nodes[nu].r - nodes[nu].l > 1)
{
nodes[nu].lcover = nodes[2 * nu].lcover;
nodes[nu].rcover = nodes[2 * nu + 1].rcover;
nodes[nu].seg = nodes[2 * nu].seg + nodes[2 * nu + 1].seg - nodes[2 * nu].rcover * nodes[2 * nu + 1].lcover;
}
else
{
nodes[nu].lcover = false;
nodes[nu].rcover = false;
nodes[nu].seg = 0;
}
}