非常经典和有难度到一道题
我也觉得论文写的太罗嗦了
这篇解题报告不错
http://www.cppblog.com/abilitytao/archive/2012/06/11/120927.html
核心思想:
1.对y进行离散化建树
2.x排序扫描线,注意求周长需要多乘以一个“团数”,即代码中的segnums
3.线段树到更新操作是难点
#include <iostream>
#include <vector>
#include <map>
#include <list>
#include <set>
#include <deque>
#include <stack>
#include <queue>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <cstdio>
#include <iomanip>
#include <cmath>
using namespace std;
///宏定义
const int INF = 20000000;
const int maxn = 10010;
const int MAXN = 10010;
///全局变量 和 函数
struct line
{
int xpos;
int y1pos, y2pos;
int flag;
}lines[maxn * 2];
struct node
{
int lc, rc;//左右下
int sum;//当前的长度
int length;//可能到总长度
bool lflag, rflag;//左右覆盖
int segnums;//线段到数目
int cover;//被覆盖到次数
node ()
{
lc = rc = 0;
length = 0;
lflag = rflag = false;
sum = segnums = cover = 0;
}
}tree[maxn * 2];
int yypos[maxn];//记录y下标,需要去重
///变量
int x11, y11, x22, y22;
///函数
int cmp(line l1, line l2)
{
return l1.xpos < l2.xpos;
}
void buildtree(int l, int r, int pos)
{
tree[pos].lc = l;
tree[pos].rc = r;
tree[pos].length = yypos[r] - yypos[l];
tree[pos].lflag = tree[pos].rflag = false;
if(l + 1 == r)
return;
int mid = (l + r) / 2;
buildtree(l, mid, pos * 2);
buildtree(mid, r, pos * 2 + 1);
}
void updatelen(int pos)
{
if(tree[pos].cover > 0)
tree[pos].sum = tree[pos].length;//完全覆盖,长度赋值为最大
else if (tree[pos].rc - tree[pos].lc > 1)
tree[pos].sum = tree[pos * 2].sum + tree[pos * 2 + 1].sum;//没有完全覆盖且不是叶子结点,长度为子树之和
else
tree[pos].sum = 0;//覆盖书为0且是叶子,长度为0
}
void updatesegnum(int pos)
{
if(tree[pos].cover > 0)//覆盖数大于0,即完全覆盖
{
tree[pos].lflag = tree[pos].rflag = true;//左右端点都已经覆盖
tree[pos].segnums = 1;//“团数"置1
}
else if(tree[pos].rc - tree[pos].lc > 1)
{
tree[pos].lflag = tree[pos * 2].lflag;
tree[pos].rflag = tree[pos * 2 + 1].rflag;
tree[pos].segnums = tree[pos * 2].segnums + tree[pos * 2 + 1].segnums - tree[pos * 2].rflag * tree[pos * 2 + 1].lflag;//关键,没有完全覆盖的情况下计算“团数”
}
else//没有覆盖的叶子结点
{
tree[pos].lflag = tree[pos].rflag = false;
tree[pos].segnums = 0;
}
}
void insert(line e, int pos) //插入操作,算法核心部分
{
//如果匹配,则覆盖长度,覆盖数目加1
if(yypos[tree[pos].lc] == e.y1pos && yypos[tree[pos].rc] == e.y2pos)
{
tree[pos].cover++;
}
else
{
int mid= (tree[pos].lc + tree[pos].rc) >> 1;
if(e.y2pos <= yypos[mid])
insert(e, pos * 2);
else if(e.y1pos >= yypos[mid])
insert(e, pos * 2 + 1);
else
{
line temp = e;
temp.y2pos = yypos[mid];
insert(temp, pos * 2);
temp = e;
temp.y1pos = yypos[mid];
insert(temp, pos * 2 + 1);
}
}
updatelen(pos);
updatesegnum(pos);
}
void del(line e, int pos)
{
if(yypos[tree[pos].lc] == e.y1pos && yypos[tree[pos].rc] == e.y2pos)
{
tree[pos].cover--;
}
else
{
if(e.y1pos >= yypos[tree[2 * pos + 1].lc])
del(e, pos * 2 + 1);
else if(e.y2pos <= yypos[tree[pos * 2].rc])
del(e, pos * 2);
else
{
line temp = e;
temp.y2pos = yypos[tree[pos * 2].rc];
del(temp, pos * 2);
temp = e;
temp.y1pos = yypos[tree[pos * 2 + 1].lc];
del(temp, pos * 2 + 1);
}
}
updatelen(pos);
updatesegnum(pos);
}
int main()
{
///变量定义
int numbers;
int i, j;
///
while(scanf("%d", &numbers) != EOF)
{
int nums = 0;
int ynums = nums;
int line_cnt = 0;
for(i = 0; i < numbers; i++)
{
scanf("%d %d %d %d", &x11, &y11, &x22, &y22);
lines[line_cnt].xpos = x11;
lines[line_cnt].y1pos = y11;
lines[line_cnt].y2pos = y22;
lines[line_cnt].flag = 1;
yypos[line_cnt++] = y11;
lines[line_cnt].xpos = x22;
lines[line_cnt].y1pos = y11;
lines[line_cnt].y2pos = y22;
lines[line_cnt].flag = -1;
yypos[line_cnt++] = y22;
}
ynums = line_cnt;
sort(yypos, yypos + ynums);
ynums = unique(yypos, yypos + ynums) - yypos;//去重,STL的unique函数
sort(lines, lines + line_cnt, cmp);
buildtree(0, ynums - 1, 1);
int ans = 0;
int Lsum = 0;//记录上一次到长度
for(i = 0; i < line_cnt - 1; i++)
{
if(lines[i].flag == 1)
insert(lines[i], 1);
else
del(lines[i], 1);
ans += tree[1].segnums * (lines[i + 1].xpos - lines[i].xpos) * 2;
ans += abs(tree[1].sum - Lsum);
Lsum = tree[1].sum;
}
del(lines[i], 1);
ans += abs(tree[1].sum - Lsum);
printf("%d\n", ans);
}
///结束
return 0;
}