折腾快一天了都,磕磕绊绊地看看人家代码看看解释,自己画图输出中间过程,差不多都理解了, = = T T。。。
应该算是有两种做法。
1、直接离散化后先算平行于 Y 轴的矩形并后的线段,然后算X轴的。这个就是插入一条线段,删除一条线段,代码比较长。
2、陈宏WC99论文《数据结构的选择与算法效率——从IOI98试题PICTURE谈起》,太长了,没怎么看懂。不过从网上搜了些这题的题解,大致看懂了。
我就说下我对这种做法的理解,比较水。。。
这个题的线段树需要更新多个域。就我的代码来讲,Tnode(也就是我的线段树节点)中的:
1、l,r 跟往常线段树一样,是离散化后的下标。
2、len,当前节点的子树中覆盖的线的长度。
3、num,子树中被分为几段,这个主要是为了计算平行于X轴的线段长度。
4、cover,标记当前节点是否被覆盖。
5、rb lb 是标记当前节点的右端点和左端点是否被覆盖。找num的数量需要用到。
Sline结构体是扫描线,其中的flag标记是入边还是出边。
具体过程:前期处理过程和矩形面积并没啥区别(不会的话先去学那个,那个简单多了= =),关键是线段树上域的更新,更新num的时候,注意,如果两个线段是连一起的,那么需要减1(可以用rb 和lb判断),因为这个len是当前的总长度,所以求线段长度的时候,就需要当前总长度减去更新前的总长度(的绝对值),也就是这次扫描线后的长度。
嗯。。大致也就理解这么多了,线段树变形太多了,呜呜。。。任重而道远!!
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <stack>
#include <climits>
#define MID(x,y) ((x+y)>>1)
#define L(x) ( x << 1 )
#define R(x) ( x << 1 | 1 )
#define BUG printf("here!!!\n");
using namespace std;
const int MAX = 5010;
struct Tnode{ int l,r,num,len,cover;bool lb,rb;};
struct Sline{ int x,y1,y2,flag;};
Tnode node[MAX<<2];
Sline l[MAX<<1];
int y[MAX<<1];
void add_line(int x1,int y1,int x2,int y2,int &cnt)
{
l[cnt].x = x1; l[cnt].y1 = y1; l[cnt].y2 = y2; l[cnt].flag = 1;
y[cnt++] = y1;
l[cnt].x = x2; l[cnt].y1 = y1; l[cnt].y2 = y2; l[cnt].flag = -1;
y[cnt++] = y2;
}
void init()
{
memset(node,0,sizeof(node));
}
void Build(int t,int l,int r)
{
node[t].l = l; node[t].r = r;
node[t].num = 0;
if( l == r - 1 ) return ;
int mid = MID(l,r);
Build(R(t),mid,r);
Build(L(t),l,mid);
}
void Updata_len(int t)
{
if( node[t].cover > 0 )
{
node[t].num = node[t].lb = node[t].rb = 1;
node[t].len = y[node[t].r] - y[node[t].l];
}
else
if( node[t].l == node[t].r - 1 )
node[t].rb = node[t].lb = node[t].len = node[t].num = 0;
else
{
node[t].rb = node[R(t)].rb; node[t].lb = node[L(t)].lb;
node[t].len = node[L(t)].len + node[R(t)].len;
node[t].num = node[L(t)].num + node[R(t)].num - node[R(t)].lb*node[L(t)].rb;
} //两线段重合的话,得减一下。。
}
void Updata(int t,Sline p)
{
if( y[node[t].l] >= p.y1 && y[node[t].r] <= p.y2 )
{
node[t].cover += p.flag;
Updata_len(t);
return ;
}
if( node[t].l == node[t].r - 1 ) return ;
int mid = MID(node[t].l ,node[t].r);
if( p.y1 <= y[mid] ) Updata(L(t),p);
if( p.y2 > y[mid] ) Updata(R(t),p);
Updata_len(t);
}
int solve(int n,int cnt,Sline *l)
{
init();
Build(1,0,cnt-1);
int ans = 0,last = 0,lines = 0;
for(int i=0; i<n; i++)
{
Updata(1,l[i]);
if( i >= 1 )
ans += 2 * lines * (l[i].x - l[i-1].x);//计算平行于x轴的长度
ans += abs(node[1].len - last); // 计算平行于y轴的长度
last = node[1].len;
lines = node[1].num;
}
return ans;
}
bool cmp(Sline a,Sline b)
{
if( a.x == b.x ) return a.flag > b.flag;
return a.x < b.x;
}
int main()
{
int n,x1,x2,y1,y2;
while( ~scanf("%d",&n) )
{
if( n == 0 )
{
printf("0\n");
continue;
}
int cnt = 0;
for(int i=0; i<n; i++)
{
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
add_line(x1,y1,x2,y2,cnt);
}
sort(y,y+cnt);
sort(l,l+cnt,cmp);
int t = cnt;
t = unique(y,y+cnt) - y;
int ans = solve(cnt,t,l);
printf("%d\n",ans);
}
return 0;
}