GDUT 专题五 G - Mayor‘s posters (离散化(清晰实现) + 线段树)2022

本文介绍了一种使用线段树解决区间更新问题的算法,具体场景是选举墙上的海报覆盖问题。每个候选人只能放置一张海报,且海报宽度可变,覆盖连续的墙段。题目要求计算所有海报放置后,有多少张海报至少部分可见。通过离散化和线段树,实现了高效的空间优化和更新查询,最终统计可见海报数量。

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

题目链接:https://vjudge.net/contest/479523#problem/G
题面:
The citizens of Bytetown, AB, could not stand that the candidates in the mayoral election campaign have been placing their electoral posters at all places at their whim. The city council has finally decided to build an electoral wall for placing the posters and introduce the following rules:
Every candidate can place exactly one poster on the wall.
All posters are of the same height equal to the height of the wall; the width of a poster can be any integer number of bytes (byte is the unit of length in Bytetown).
The wall is divided into segments and the width of each segment is one byte.
Each poster must completely cover a contiguous number of wall segments.

They have built a wall 10000000 bytes long (such that there is enough place for all candidates). When the electoral campaign was restarted, the candidates were placing their posters on the wall and their posters differed widely in width. Moreover, the candidates started placing their posters on wall segments already occupied by other posters. Everyone in Bytetown was curious whose posters will be visible (entirely or in part) on the last day before elections.
Your task is to find the number of visible posters when all the posters are placed given the information about posters’ size, their place and order of placement on the electoral wall.

input
The first line of input contains a number c giving the number of cases that follow. The first line of data for a single case contains number 1 <= n <= 10000. The subsequent n lines describe the posters in the order in which they were placed. The i-th line among the n lines contains two integer numbers li and ri which are the number of the wall segment occupied by the left end and the right end of the i-th poster, respectively. We know that for each 1 <= i <= n, 1 <= li <= ri <= 10000000. After the i-th poster is placed, it entirely covers all wall segments numbered li, li+1 ,… , ri.

output
For each input data set print the number of visible posters after all the posters are placed.

思路:这个问题为区间更新问题,我们可以用线段树。题目可以翻译为区间涂色问题,最后求整个墙面存在多少种颜色。

观察数据范围:如果暴力枚举的话至少需要超过1e7个int字节的长度,以及可能暴内存里,而n <= 1e4,所以我们可以用离散化,节省空间,提高效率;(离散化要注意,如果两个数间隔,离散化后的数据应该也保持间隔,这样才不会漏统计,具体可以参考1 ,10 1,4 7,10这组数据,如果不间隔的话就是1,4 1,2, 3,4;这就导致答案漏了一种颜色)

接下来的思路,可以参考这里

我想讲讲我的离散化和统计答案的实现思路:
构建结构体node,raw为原始值,ref为映射值,idex为编号
先按照raw升序排序,如果相邻映射值+1,如果相等映射值不变,如果存在间隔,映射值+2;
之后再进行一次排序,以idex值排序,方便我们按顺序update;
update, query函数就是线段树的模板了;
统计答案的话,就是一个bool数组,col,只有当col[tree[p]] == 0才更新ans;
另外要注意的就是数组的大小,题目数据应该不超过N = 2e5,所以我们开线段树tree[],和标记数组mar[]时的大小,应该为4 * N + 5;(血的教训,wa好几次)
具体看代码实现

AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
#define Mid ll + ((rr - ll) >> 1)
#define Lson p << 1, ll, Mid
#define Rson p << 1 | 1, Mid + 1, rr
const int N = 2e4, Inf = 0x3f3f3f3f;
int tree[4 * N + 5], mar[4 * N + 5];
int n, m, maxn, ans;
bool col[(N >> 1) + 5];
struct node
{
    int raw, ref, idex;
}a[N + 5];

inline LL read()
{
    char ch; bool flag = 0;
    while((ch = getchar()) < '0' || ch > '9')
        if(ch == '-')   flag = 1;
    LL res = ch - '0';
    while((ch = getchar()) >= '0' && ch <= '9')
        res = (res << 1) + (res << 3) + ch - '0';
    return flag ? -res : res;
}

bool cmp1(node a, node b)
{
    return a.raw < b.raw;
}

bool cmp2(node a, node b)
{
    if(a.idex == b.idex)
        return a.ref < b.ref;
    return a.idex < b.idex;
}

void pushup(int p, int ll, int rr)
{
    if(!tree[p << 1] || !tree[p << 1 | 1] || tree[p << 1] != tree[p << 1 | 1])
        tree[p] = 0;
    else    tree[p] =  tree[p << 1 | 1]; //lchild == rchild, choose whatever
}

void pushdown(int p, int ll, int rr)
{
    if(mar[p])
    {
        tree[p << 1] = tree[p << 1 | 1] = mar[p];
        mar[p << 1] = mar[p << 1 | 1] = mar[p];
        mar[p] = 0;
    }
}

void update(int l, int r, int d, int p, int ll, int rr)
{
    if(l <= ll && r >= rr)
    {
        tree[p] = d;    mar[p] = d;
        return;
    }
    pushdown(p, ll, rr);
    if(Mid >= l)    update(l, r, d, Lson);
    if(Mid < r)     update(l, r, d, Rson);
    pushup(p, ll, rr);
}

void query(int l, int r, int p, int ll, int rr)
{
    if(tree[p] > 0)
    {
        int u = tree[p];
        if(!col[u]) ++ans, col[u] = 1;
        return;
    }
    else if(tree[p] == -1)    return;
    pushdown(p, ll, rr);
    query(l, r, Lson);
    query(l, r, Rson);
}

int main()
{
    m = read();
    while(m--)
    {
        memset(tree, -1, sizeof(tree));
        memset(mar, 0, sizeof(mar));
        memset(col, 0, sizeof(col));
        maxn = -Inf;    ans = 0;
        n = read();
        for(int i = 1; i <= n; ++i)
        {
            a[i].raw = read(); a[i + n].raw = read();
            a[i].idex = a[i + n].idex = i;
        }
        sort(a + 1, a + (n << 1) + 1, cmp1);
        a[1].ref = 0;
        for(int i = 2, tmp = 0; i <= n << 1; ++i)
        {
            if(a[i].raw - a[i - 1].raw > 1)     tmp += 2;
            else if(a[i].raw != a[i - 1].raw)   ++tmp;
            a[i].ref = tmp;
            if(tmp > maxn)  maxn = tmp;
        }
        sort(a + 1, a + (n << 1) + 1, cmp2);
        for(int i = 2; i <= n << 1; i += 2)
        {
            update(a[i - 1].ref, a[i].ref, a[i].idex, 1, 0, maxn);
        }
        query(0, maxn, 1, 0, maxn);
        printf("%d\n", ans);
    }
    //system("pause");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值