数算实习 Mayor's posters 线段树 离散化

Mayor’s posters每个候选人都可以在墙上放置一张海报。

所有海报的高度都与墙的高度相同; 海报的宽度可以是任何整数个单位。
墙被分成10000000段,每段的宽度是一个单位。每张海报必须完全覆盖连续数量个单位的墙壁。
你的任务是找到所有海报放置完毕后可见海报的数量。

输入:
第一行输入包含一个数字c,给出了后面的案例数。单个案例的第一行数据包含数字1 <= n <= 10000。随后的n行按照海报的放置顺序给出海报的左端编号和右端编号。
输出:
海报粘贴完毕后能看到的海报数量

样例输入
1
5
1 4
2 6
8 10
3 4
7 10

样例输出
4

#include <iostream>
#include <algorithm>
using namespace std;

int sum;
int flag;

struct post
{
	int l;
	int r;
};
struct cnode
{
	int l;
	int r;
	bool covered;
	cnode *left;
	cnode *right;
};
struct section
{
	int l;
	int r;
};

void buildtree(cnode* root, section* s, int le, int ri)
{
	root->covered = 0;
	if (le == ri)
		return;
	root->left = new cnode;
	root->right = new cnode;
	int mid = (le + ri) / 2;
	root->left->l = s[le].l;
	root->left->r = s[mid].r;
	root->right->l = s[mid + 1].l;
	root->right->r = s[ri].r;
	buildtree(root->left, s, le, mid);
	buildtree(root->right, s, mid + 1, ri);
}

void quary(cnode* root, int L, int R)
{
	if (root->l == L && root->r == R)
	{
		if (root->covered == 1)
			return;
		else
		{
			root->covered = 1;
			flag = 1;
			return;
		}
	}
	else
	{
		if (root->covered == 1)
			return;
		if (R <= (root->left->r))
		{
			quary(root->left, L, R);
		}
		else if (L >= (root->right->l))
		{
			quary(root->right, L, R);
		}
		else
		{
			quary(root->left, L, root->left->r);
			quary(root->right, root->right->l, R);
		}
		if (root->left->covered == 1 && root->right->covered == 1)
			root->covered = 1;
	}
}

int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		post p[10002];              //记录海报信息
		int point[50004];           //记录端点值
		section s[50004];           //记录单位区间
		sum = 0;
		int n;
		cin >> n;
		int j = 0;
		for (int i = 1; i <= n; ++i)
		{
			cin >> p[i].l >> p[i].r;
			point[j++] = p[i].l;
			point[j++] = p[i].r;
		}
		sort(point, point + j);
		int len = 1;
		for (int k = 0; k < j - 1; k++)                      //离散化
		{
			if (point[k] != point[k + 1])
			{
				if (point[k + 1] - 1 == point[k])
				{
					s[len].l = point[k];
					s[len].r = point[k];
					len++;
				}
				else
				{
					s[len].l = point[k];
					s[len].r = point[k];
					len++;
					s[len].l = point[k] + 1;
					s[len].r = point[k + 1] - 1;
					len++;
				}
			}
		}
		s[len].l = point[j - 1];
		s[len].r = point[j - 1];
		cnode* root = new cnode;         
		root->l = s[1].l;
		root->r = s[len].r;
		buildtree(root, s, 1, len);
		for (int i = n; i >= 1; --i)
		{
			flag = 0;
			int L = p[i].l;
			int R = p[i].r;
			quary(root, L, R);
			sum += flag;
		}
		cout << sum << endl;
	}

	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值