POJ 3225 - Help with Intervals

Advanced Data Structures :: Segment Tree


Description

把集合想象成区间来看这道题。
四种运算符,五种表达式,无尽的区间操作。
刚开始,你拥有的是一个空集。
输入并执行灰常多的区间操作。
输出最终你拥有的集合。


Type

Advanced Data Structures :: Segment Tree


Analysis

对于这道题目,如果想到线段树,

很容易的就可以把整个区间映射到线段树上(毕竟线段树也叫区间树)。

然而我们面对的第一个问题是,如果去操作我们的区间。


其实这个问题只是稍微费点脑力而已。

将每个叶子结点定为boolean,表示我们是否拥有这个点。

我们便有了一些基本的操作——将一段区间赋值为true,或者flase。

还有一种操作比较特别——将一段区间的值取反。


然后,对于题目给的五种命令,我们都可以找到对应的操作线段树的方法。

  • U T:将T区间赋值为true。
  • I T:将T补集区间赋值为false。
  • D T:将T区间赋值为false。
  • C T:将T区间取反,T补集区间赋值为false。
  • S T:将T区间取反。
然后,我们将命令映射到每个方法上,就可以用线段树来解决了。


但是,这题还有第二个难点。

之所以一开头就把集合看成区间在于,这题所操作的元素,是线,而不是点。

这就导致像(1, 2)这种区间是有意义的,它表示了点1到点2不含顶点的线。

因此,线段树经常碰见的离散化问题又来了。

对于这种经典的,要把常规思维中的点变成线的问题,

我们的办法,就是将每个点倍增,这意味着,例如我们存储了{ 1, 2, 3, 4, 5}

代表了我们拥有的是(0,3),分开来讲,就是

(0, 1)、1、(1, 2)、2、(2, 3)。

如此一来,离散化工作便完成了。


还有一点需要注意,输入中的区间(a, b),由于a <= b,

可能出现类似(2, 2)这样的区间,应看成空。



Solution

// POJ 2528
// Mayor's posters
// by A Code Rabbit

#include <algorithm>
#include <cstdio>
#include <cstring>

using namespace std;

#define LSon(x) ((x) << 1)
#define RSon(x) ((x) << 1 | 1)

const int MAXN = 10002;
const int ROOT = 1;

struct Seg {
    int w;
    int flag;
};

struct SegTree {
    Seg node[MAXN * 4 << 2];
    void Build() { memset(node, 0, sizeof(node)); }
    void Push(int pos) {
        Seg& father = node[pos];
        Seg& lson = node[LSon(pos)];
        Seg& rson = node[RSon(pos)];
        if (father.flag) {
            lson.flag = rson.flag = father.flag;
            lson.w = rson.w = father.flag;
            father.flag = 0;
        }
    }
    void Modify(int l, int r, int pos, int x, int y, int z) {
        if (x <= l && r <= y) {
            node[pos].w = z;
            node[pos].flag = z;
            return;
        }
        Push(pos);
        int m = l + r >> 1;
        if (x <= m) Modify(l, m, LSon(pos), x, y, z);
        if (y > m) Modify(m + 1, r, RSon(pos), x, y, z);
    }
    void Query(int l, int r, int pos, bool* bo) {
        if (l == r) {
            bo[node[pos].w] = true;
            return;
        }
        Push(pos);
        int m = l + r >> 1;
        Query(l, m, LSon(pos), bo);
        Query(m + 1, r, RSon(pos), bo);
    }
};

struct Poster {
    int l, r;
};

int n;
Poster poster[MAXN];

int* pointer[MAXN << 2];
bool bo[MAXN];
SegTree tree;

bool CMP(int* x, int* y) {
    return *x < *y;
}

int main() {
    int tot_case;
    scanf("%d", &tot_case);
    while (tot_case--) {
        // Input.
        scanf("%d", &n);
        for (int i = 0; i < n; i++) {
            scanf("%d%d", &poster[i].l, &poster[i].r);
            pointer[i * 2] = &poster[i].l;
            pointer[i * 2 + 1] = &poster[i].r;
        }
        // Discretization.
        sort(pointer, pointer + 2 * n, CMP);
        int num_bytes = 1;
        for (int i = 0; i < 2 * n - 1; i++) {
            int tmp = num_bytes;
            if (*pointer[i] != *pointer[i + 1]) {
                if (*pointer[i] + 1 == *pointer[i + 1])
                    num_bytes += 1;
                else
                    num_bytes += 1;
                    /* the correct answer should be: "num_bytes += 2;". */
            }
            *pointer[i] = tmp;
        }
        *pointer[2 * n - 1] = num_bytes;
        // Stick posters by the segments tree.
        tree.Build();
        int num_posters = 1;
        for (int i = 0; i < n; i++)
            tree.Modify(1, num_bytes, ROOT, poster[i].l, poster[i].r, num_posters++);
        // Compute and output.
        memset(bo, false, sizeof(bo));
        tree.Query(1, num_bytes, ROOT, bo);
        int sum = 0;
        for (int i = 0; i < num_posters; i++)
            if (bo[i])
                sum++;
        printf("%d\n", sum);
    }

    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值