poj 1177 求矩形周长 IOI 98

非常经典和有难度到一道题

我也觉得论文写的太罗嗦了

这篇解题报告不错

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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值