POJ 2528 Mayor's posters

博客围绕POJ 2528 Mayor’s posters题目展开,该题是给定N个海报及覆盖区域,求最后被覆盖区域数量。采用线段树算法,介绍了线段树节点附加信息含义、三个函数(build、update、cal)的作用,还提及因l、r值长需进行离散化处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

POJ 2528 Mayor’s posters

题目链接

Description

给N个海报,每个海报有L,R,表示这块区域被覆盖,问最后有多少块区域被覆盖

Algorithm

线段树

每个节点的附加信息v的意义是

  • 这块区域没有任何一个海报覆盖 v = 0
  • 这块区域(不完全重合)有不止一块海报覆盖 v = 0
  • 这块区域只有一块海报覆盖 v = i (i 为第 i 个海报)

线段树三个函数

  • build 建树,没什么好说

  • update

    • 如果完全覆盖,就更新v

    • 否则就把root的两个子节点变成v 同时把该root节点变成0

    • 向下递归更新 注意是三种情况

  • cal 最后统计被覆盖的区域数

    • 如果 v > 0 表示这块区域被海报 v 完全覆盖 ans++, 注意用used记录
    • v = 0 则向下递归

离散化

本题l,r很长,所以需要离散化,实际上离散化的代码并不长,具体可看代码

#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAXN = 10000 + 9;
pair<int, int> a[MAXN], b[MAXN];
vector<int> v;
bool used[MAXN];
int getId(int x)
{
	return lower_bound(v.begin(), v.end(), x) - v.begin() + 1;
}
struct Node
{
	int l, r, v;
};
Node tree[10 * MAXN];
void build(int root, int l, int r)
{
	tree[root].l = l;
	tree[root].r = r;
	tree[root].v = 0;
	if (l == r) return;
	int mid = (l + r) / 2;
        build(2 * root, l, mid);
        build(2 * root + 1, mid + 1, r);
}
void update(int root, int l, int r, int v)
{
	// << root << ' ' << l << ' ' << r << ' ' << v << ' ' << tree[root].l << ' ' << tree[root].r << endl;
        if (tree[root].l == l && tree[root].r == r) {
		tree[root].v = v;
		return;
        }
        if (tree[root].v != 0) {
		tree[2 * root].v = tree[root].v;
		tree[2 * root + 1].v = tree[root].v;
		tree[root].v = 0;
        }
        int mid = (tree[root].l + tree[root].r) / 2;
        if (r <= mid) {
		update(root * 2, l, r, v);
		return;
        }
        if (l > mid) {
		update(root * 2 + 1, l, r, v);
		return;
        }
        update(root * 2, l, mid, v);
        update(root * 2 + 1, mid + 1, r, v);
}
int ans = 0;
void cal(int root)
{
	if (tree[root].v > 0) {
		if (!used[tree[root].v]) {
			ans++;
			used[tree[root].v] = true;
		}
		return;
	}
	cal(2 * root);
	cal(2 * root + 1);
}
void solve()
{
	v.clear();
	int n;
	scanf("%d", &n);
	for (int i = 0; i < n; i++) {
		int l, r;
		scanf("%d%d", &l, &r);
                v.push_back(l);
                v.push_back(r);
                a[i].first = l;
                a[i].second = r;
	}
	sort(v.begin(), v.end());
	v.erase(unique(v.begin(), v.end()), v.end());
	for (int i = 0; i < n; i++) {
		b[i].first = getId(a[i].first);
		b[i].second = getId(a[i].second);
	}
	build(1, 1, v.size());
	for (int i = 0; i < n; i++) {
                update(1, b[i].first, b[i].second, i + 1);
	}
	memset(used, 0, sizeof(used));
	ans = 0;
	cal(1);
	cout << ans << endl;
}
int main()
{
	//freopen("in.txt", "r", stdin);
	int t;
	scanf("%d", &t);
	while (t--) {
		solve();
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值