ACM/ICPC 之 数据结构-线段树+区间离散化(POJ2528)

  这道题用线段树做更方便更新和查询,但是其数据范围很大,因此要将离散化和线段树结合起来,算是一道比较经典的线段树+离散化的例题。

线段树的离散化有很多方法,在这里,我先用一次结点离散化,间接将源左右端点离散化的想法实现。(受到一个博客的启发)


 

  题意:贴海报-给出海报左右端点,然后顺序贴上,问最后有多少海报可见。

  直接贴上Code,具体解释在注释中有提及(有不懂的地方可以在纸上打个线段树草稿试试):

 

//贴海报-给出海报左右端点,顺序贴上,问最后有多少海报可见。
//Time:79Ms	Memory:2712K
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;

#define MAX 10005

struct Node {
	int l, r, kind;
}tr[16*MAX];	//两端点加空点需要8-16*MAX数据量

struct Pos {
	int num, id;
	friend bool operator < (Pos p1, Pos p2) { return p1.num < p2.num; }
}pos[2*MAX];

int n, cnt;
int l[MAX], r[MAX];
bool v[MAX];

void build(int x,int l,int r)
{
	tr[x].l = l;	tr[x].r = r;
	if (l == r)	return;
	int mid = (l + r) / 2;
	build(2 * x, l, mid);
	build(2 * x + 1, mid + 1, r);
}

void update(int x,int l,int r,int k)
{
	if (tr[x].l == l && tr[x].r == r) {
		tr[x].kind = k;
		return;
	}
	if (tr[x].kind) {
		tr[2 * x].kind = tr[x].kind;
		tr[2 * x + 1].kind = tr[x].kind;
		tr[x].kind = 0;
	}
	int mid = (tr[x].l + tr[x].r) / 2;
	if (r <= mid)	update(2 * x, l, r, k);
	else if (l > mid)	update(2 * x + 1, l, r, k);
	else {
		update(2 * x, l, mid, k);
		update(2 * x + 1, mid + 1, r, k);
	}
}

int query(int x,int l,int r)
{
	if (tr[x].kind) {
		if (v[tr[x].kind])	return 0;
		else { v[tr[x].kind] = true; return 1;}
	}
	if (tr[x].l == tr[x].r) return 0;	//由于有空点,可能会有tr[x].kind = 0
	int mid = (tr[x].l + tr[x].r) / 2;
	return query(2 * x, l, mid) + query(2 * x + 1, mid + 1, r);
}

int main()
{
	int T;
	scanf("%d", &T);
	while (T--) {
		memset(tr, 0, sizeof(tr));
		memset(v, 0, sizeof(v));
		scanf("%d", &n);
		for (int i = 0; i < n; i++)
		{
			scanf("%d%d", &l[i], &r[i]);
			pos[2 * i].num = l[i];
			pos[2 * i + 1].num = r[i];
			pos[2 * i].id = 2 * i;	//偶数-左端点
			pos[2 * i + 1].id = 2 * i + 1;	//奇数-右端点
		}
		int last = pos[0].num;
		cnt = 1;
		sort(pos, pos + 2 * n);
		for (int i = 0; i < 2 * n; i++)
		{
			if (last != pos[i].num) {
				if (pos[i].num - last > 1)	
					cnt++;	//不相邻时,中间空一点
				cnt++;
				last = pos[i].num;
			}
			int id = pos[i].id;	//分别对左右端点离散化
			id % 2 ? r[id/2] = cnt : l[id/2] = cnt;
		}
		build(1, 1, cnt);
		for (int i = 0; i < n; i++)
			update(1, l[i], r[i], i + 1);
		printf("%d\n", query(1, 1, cnt));
	}
	
	return 0;
}

 

posted @ 2015-11-04 20:03  文字失效  阅读(509)  评论(0编辑  收藏  举报