POJ2528 Mayor's posters(线段树)

题目链接:poj2528

题意:

n张等高的海报,贴在一堵无限长度的墙上,给出海报的起始坐标,海报张贴的顺序,海报会被覆盖,问最后能看见多少不同的海报。

思路:

海报的下标最大为1000W,线段树是存不下的,但是海报的数量只有10000,可以利用离散化技巧,把这10000个海报的起始下标重新分配序号,再用线段树维护。
这里是区间更新,整个区间置为一个值(其实只需要维护一个懒标记就可以了)。查询的时候,要跑遍整棵树上被打了标记的点,用一个vis数组判断这个颜色是否已经被访问过。

小结

想起去年离散化不怎么理解,现在很熟练就写出来了。。。但是这题依旧WA了我n发。。。看了无数遍没有找出原因,最后没想到是push down的时候,没有判断当前节点是否打了懒标记就往下push。。。回去把第一发WA的改了也过了。。。


PS

这题数据比较水。离散化的时候当两个点之间差距大于1时,要往里面加一个点。


代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <map>
#include <algorithm>

using namespace std;

const int maxn = 40000 + 10;

struct Node
{
    int le, ri;
    Node(){}
    Node(int le, int ri):le(le), ri(ri){}
}A[maxn];


bool vis[maxn];
int color[maxn<<2];
int v[maxn];


void pushdown(int rt){
    if(color[rt]!=-1){
        color[rt<<1] = color[rt];
        color[rt<<1|1] = color[rt];
        color[rt] = -1;
    }
}

void Set(int rt, int a, int b, int l, int r, int x){
    if(a<=l && r<=b){
        color[rt] = x;
    }
    else{
        int mid = (l+r)>>1;
        pushdown(rt);
        if(a<=mid) Set(rt<<1, a, b, l, mid, x);
        if(mid<b) Set(rt<<1|1, a, b, mid+1, r, x);
    }
}

int query(int rt, int l, int r){
    if(color[rt]==-1){
        int mid = (l+r)>>1;
        if(l==r)
            return 0;
        else
            return query(rt<<1, l, mid) + query(rt<<1|1, mid+1, r);
    }
    else{
        if(vis[color[rt]])
            return 0;
        else{
            vis[color[rt]] = 1;
            return 1;
        }
    }
}

int main(){
    int t, n;
    scanf("%d", &t);
    while(t--){
        scanf("%d", &n);
        int cnt = 0;
        memset(vis, 0, sizeof(vis));
        memset(color, -1, sizeof(color));
        for(int i=0; i<n; ++i){
            scanf("%d%d", &A[i].le, &A[i].ri);
            v[cnt++] = A[i].le;
            v[cnt++] = A[i].ri;
        }
        sort(v, v+cnt);
        cnt = unique(v, v+cnt) - v;

        int tmp_cnt = cnt;
        for(int i=1; i<cnt; ++i){
            if(v[i] - v[i-1] > 1) v[tmp_cnt++] = v[i-1] + 1;
        }

        sort(v, v+tmp_cnt); 

        cnt = unique(v, v+tmp_cnt) - v;

        for(int i=0; i<n; ++i){
            int le = lower_bound(v, v+cnt, A[i].le) - v + 1;
            int ri = lower_bound(v, v+cnt, A[i].ri) - v + 1;
            Set(1, le, ri, 1, cnt, i+1);
        }

        printf("%d\n", query(1, 1, cnt));
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值