poj 1177 Picture(走査線+矩形周長並)


http://poj.org/problem?id=1177
長方形の周長を求め、明確な点は、覆われたエッジの長さを無視することです.
面積を求めるのと同様に,まず離散化し,矩形の各横辺を下から上へ走査した.スキャン中に3つのタスクを完了し、対応する区間情報を更新し、横辺長を求め、縦辺長を求める.
ノード情報:
l,r:左右区間番号
cnt:この区間が完全にカバーされているかどうかを示す.cnt>0は完全上書きを表し、そうでなければ完全上書きではありません.
lp,rp:この区間の2つの端点が上書きされているか否かを示し,1が上書きされ,0が上書きされていない.
num:この区間が覆われている線分の数.例えば区間[1,10]では、num=1は[2,3][3,5]が更新されると連続するので、num=2は[1,2][3,5]が更新されるとnum=2となり、この2つの線分が連続しないためである.レコードnumは、縦エッジを求めるため、1つのエッジをスキャンするたびに増加する縦エッジの数は2*numです.
1つのエッジをスキャンするたびに、現在の総区間の長さから前の総区間の長さを減算して絶対値をとるのが、今回増加した横辺の長さです.(次のエッジの高さ-このエッジの高さ)*num*2は、増加した縦エッジ長です.
わかりやすい説明:http://www.cnblogs.com/scau20110726/archive/2013/04/13/3018687.html
#include <stdio.h>
#include <iostream>
#include <map>
#include <set>
#include <list>
#include <stack>
#include <vector>
#include <math.h>
#include <string.h>
#include <queue>
#include <string>
#include <stdlib.h>
#include <algorithm>
#define LL long long
#define _LL __int64
#define eps 1e-12
#define PI acos(-1.0)
using namespace std;
const int maxn = 5010;

struct Line
{
	int x1,x2,y;
	int tag;
	bool operator < (const struct Line &tmp)const
	{
		return y < tmp.y;
	}
}line[maxn*2];

int x[maxn*2];

struct node
{
	int l,r,cnt,len;
	int lp,rp,num;
}tree[maxn*8];

int Binsearch(int l, int r, int key)
{
	int low = l,high = r;
	while(high >= low)
	{
		int mid = (low + high) >> 1;
		if(x[mid] == key)
			return mid;
		if(x[mid] > key)
			high = mid-1;
		else low = mid+1;
	}
	return -1;
}

void build(int v, int l, int r)
{
	tree[v].l = l;
	tree[v].r = r;
	tree[v].cnt = 0;
	tree[v].len = 0;
	tree[v].lp = tree[v].rp = tree[v].num = 0;
	if(l == r)
		return;
	int mid = (l+r)>>1;
	build(v*2,l,mid);
	build(v*2+1,mid+1,r);
}

void maintain(int v)
{
	if(tree[v].cnt > 0) //     
	{
		tree[v].len = x[tree[v].r+1] - x[tree[v].l];
		tree[v].lp = 1;
		tree[v].rp = 1;
		tree[v].num = 1;
		return;
	}
	if(tree[v].l == tree[v].r)
	{
		tree[v].lp = tree[v].rp = tree[v].num = tree[v].len = 0;
		return;
	}
	//         
	tree[v].len = tree[v*2].len + tree[v*2+1].len;
	tree[v].lp = tree[v*2].lp;
	tree[v].rp = tree[v*2+1].rp;
	tree[v].num = tree[v*2].num + tree[v*2+1].num - (tree[v*2].rp&&tree[v*2+1].lp);
}

void update(int v, int l, int r, int tag)
{
	if(tree[v].l == l && tree[v].r == r)
	{
		tree[v].cnt += tag;
		maintain(v);
		return;
	}

	int mid = (tree[v].l + tree[v].r) >> 1;
	if(r <= mid)
		update(v*2,l,r,tag);
	else if(l > mid)
		update(v*2+1,l,r,tag);
	else
	{
		update(v*2,l,mid,tag);
		update(v*2+1,mid+1,r,tag);
	}
	maintain(v);
}

int main()
{
	int n;
	int cnt,x1,y1,x2,y2;

	while(~scanf("%d",&n))
	{
		cnt = 0;
		for(int i = 1; i <= n; i++)
		{
			scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
			line[++cnt] = (struct Line){x1,x2,y1,1};
			x[cnt] = x1;
			line[++cnt] = (struct Line){x1,x2,y2,-1};
			x[cnt] = x2;
		}
		sort(x+1,x+1+cnt);
		sort(line+1,line+1+cnt);

		int k = 1;
		for(int i = 2; i <= cnt; i++)
		{
			if(x[i] != x[i-1])
				x[++k] = x[i];
		}
		build(1,1,k);
		int ans = 0;
		int pre = 0;
		for(int i = 1; i <= cnt; i++)
		{
			int l = Binsearch(1,k,line[i].x1);
			int r = Binsearch(1,k,line[i].x2)-1;
			update(1,l,r,line[i].tag);
			int t = abs(tree[1].len - pre);
			pre = tree[1].len;
			ans += t;
			if(i < cnt)
				ans += (line[i+1].y-line[i].y)*2*tree[1].num;
		}
		printf("%d
",ans); } return 0; }