D - Mayor's posters——线段树区间覆盖+离散化

Think:
1知识点:线段树区间覆盖+离散化
2题意分析:竞选人需要在墙上贴宣传海报,海报高度相同宽度不一定相同,按照时间轴会出现覆盖,给定按照时间轴海报的起始位置和终止位置,询问在最终状态会展现多少海报,n([1, 10000]),(li, ri)([1, 10000000]),参考前辈博客,因l(ri-li+1)与n差值较大,因此需要离散化
eg1:
离散化前坐标:[1,6] [1.7] [2,10] [8 18]
排序:1 1 2 6 7 8 10 18
离散化: 1 2 3 4 5 6 7
离散化后坐标:[1,3] [1,4] [2,6] [5,7]
进而再逆着判断,这样只需判断当前结点区间是否已经覆盖即可
3反思:注意数组不要开的过小

vjudge题目链接

以下为Accepted代码

/*线段树区间覆盖+离散化*/
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 11400;

struct Node{
    int id, x;
}node[N<<1];

struct Tree{
    int l, r, vis;
}tree[N<<3];

int flag;

void Build(int l, int r, int rt);/*初始建树*/
void find(int L, int R, int rt);/*区间覆盖信息查询*/
void Updata(int rt);/*树结点信息更新*/
bool cmp1(struct Node a, struct Node b);
bool cmp2(struct Node a, struct Node b);

int main(){
    int T, n, i, ans;
    scanf("%d", &T);
    while(T--){
        scanf("%d", &n);
        for(i = 1; i <= n<<1; i += 2){
            scanf("%d %d", &node[i].x, &node[i+1].x);
            node[i].id = node[i+1].id = i;
        }
        sort(node+1, node+1+(n<<1), cmp1);
        int pre = 0, cnt = 0;
        for(i = 1; i <= n<<1; i++){/*离散化*/
            if(node[i].x == pre){
                node[i].x = cnt;
            }
            else {
                pre = node[i].x;
                node[i].x = ++cnt;
            }
        }
        Build(1, n<<1, 1);/*2倍n——why?*/
        sort(node+1, node+1+(n<<1), cmp2), ans = 0;
        for(i = 1; i <= n<<1; i += 2){/*逆贴,判断查询区间是否已经覆盖即可*/
            flag = 0;
            find(node[i].x, node[i+1].x, 1);
            if(flag) ans++;
        }
        printf("%d\n", ans);
    }
    return 0;
}
bool cmp1(struct Node a, struct Node b){
    return a.x < b.x;
}
bool cmp2(struct Node a, struct Node b){
    if(a.id != b.id) return a.id > b.id;
    else return a.x < b.x;
}
void Build(int l, int r, int rt){/*初始建树*/
    tree[rt].l = l;
    tree[rt].r = r;
    tree[rt].vis = 0;
    if(tree[rt].l == tree[rt].r)
        return;
    int mid = (l+r)>>1;
    Build(l, mid, rt<<1);
    Build(mid+1, r, rt<<1|1);
}
void find(int l, int r, int rt){/*区间覆盖信息查询*/
    if(tree[rt].vis)
        return;
    if(tree[rt].l == l && tree[rt].r == r){
        tree[rt].vis = 1, flag = 1;
        return;
    }
    int mid = (tree[rt].l+tree[rt].r)>>1;
    if(r <= mid)
        find(l, r, rt<<1);
    else if(l > mid)
        find(l, r, rt<<1|1);
    else {
        find(l, mid, rt<<1);
        find(mid+1, r, rt<<1|1);
    }
    Updata(rt);
}
void Updata(int rt){/*树结点信息更新*/
    tree[rt].vis = tree[rt<<1].vis & tree[rt<<1|1].vis;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值