Ural1987-Nested Segments

题目上说每两条线段要么没有公共点,要么完全覆盖,而且又规定了输入顺序,因此对于某个点来说后输入的长度一定短,所以用线段树做区间更新即可。
由于数字很大,需要先做一个离散化,把线段的点和询问的点离散后更新线段树。

#include <cstdio>
#include <map>

using namespace std;

#define lchild rt << 1, l, m
#define rchild rt << 1 | 1, m + 1, r

const int maxn = 1e5 + 5;
const int sz = 2 * maxn * 4;

struct edge {
    int u, v;
};

int tree[sz];
edge e[maxn];
int q[maxn];

int n;

void push_up(int rt) {
    if (tree[rt<<1] == tree[rt<<1|1]) {
        tree[rt] = tree[rt<<1];
    } else {
        tree[rt] = -1;
    }
}

void push_down(int rt) {
    tree[rt<<1|1] = tree[rt<<1] = tree[rt];
}

void build(int rt = 1, int l = 1, int r = n) {
    tree[rt] = -1;
    if (l == r) {
        return;
    }
    int m = (l + r) >> 1;
    build(lchild);
    build(rchild);
}

void update(int i, int L, int R, int rt = 1, int l = 1, int r = n) {
    if (L <= l && r <= R) {
        tree[rt] = i;
        return;
    }
    if (tree[rt] > 0)
        push_down(rt);
    int m = (l + r) >> 1;
    if (L <= m) {
        update(i, L, R, lchild);
    }
    if (R > m) {
        update(i, L, R, rchild);
    }
    push_up(rt);
}

int query(int p, int rt = 1, int l = 1, int r = n) {
    if (l == r) {
        return tree[rt];
    }
    if (tree[rt] > 0)
        push_down(rt);
    int m = (l + r) >> 1;
    if (p <= m) {
        return query(p, lchild);
    } else {
        return query(p, rchild);
    }
}

map<int, int> mp;

int main(int argc, char const *argv[]) {
    int k, m;
    scanf("%d", &k);
    for (int i = 0; i < k; i++) {
        scanf("%d%d", &e[i].u, &e[i].v);
        mp[e[i].u] = 0;
        mp[e[i].v] = 0;
    }
    scanf("%d", &m);
    for (int i = 0; i < m; i++) {
        scanf("%d", &q[i]);
        mp[q[i]] = 0;
    }
    map<int, int>::iterator it;
    int cnt = 1;
    for (it = mp.begin(); it != mp.end(); it++) {
        it->second = cnt++;
    }
    n = mp.size();
    build();
    for (int i = 0; i < k; i++) {
        update(i+1, mp[e[i].u], mp[e[i].v]);
    }
    for (int i = 0; i < m; i++) {
        printf("%d\n", query(mp[q[i]]));
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值