数据结构--线段树&离散化可能有的问题--poj2528 Mayor's posters

给定n个区间,按顺序覆盖后,问最后几个是可见的。

l,r,范围1e7,需要离散化。

//但是注意简单的离散化可能会出现错误,给出下面两个简单的例子应该能体现普通离散化的缺陷:

//例子一:1-10 1-4 5-10

//例子二:1-10 1-4 6-10

//解决的办法则是对于距离大于1的两相邻点,中间再插入一个点

这样离散化后

例子一:[1,6] [1,3] [4,6]

例子二:[1,7] [1,3] [5,7]

转自 https://www.cnblogs.com/xuejianye/p/5694750.html

#include <cstdio>
#include <iostream>
#include <map>
#include <cstring>
#include <algorithm>
#include <iterator>
#include <vector>
using namespace std;
#define lc (rt << 1)
#define rc (rt << 1 | 1)
#define mid (l + r) / 2

const int maxn = 1e4 + 5;
struct node{
    int l,r;
    int lid,rid;
}ns[maxn];
map<int,int> mp;
map<int,int>::iterator it,pit;
int N;
int tr[maxn << 4],setv[maxn << 4];
bool vis[maxn];

void init(int l,int r,int rt)//初始设为0,统计时不计入颜色
{
    if(l == r){
        tr[rt] = setv[rt] = 0;
        return ;
    }
    init(l,mid,lc);
    init(mid + 1,r,rc);
    tr[rt] = setv[rt] = 0;
}
void pushdown(int l,int r,int rt)
{
    if(setv[rt]){
        setv[lc] = setv[rc] = setv[rt];
        tr[lc] = tr[rc] = setv[rt];
        setv[rt] = 0;
    }
}
void update(int ql,int qr,int l,int r,int rt,int x)
{
    // printf("in update %d %d %d %d %d\n",ql,qr,l,r,x);
    if(ql <= l && r <= qr){
        tr[rt] = x;
        setv[rt] = x;
        return ;
    }
    pushdown(l,r,rt);
    if(ql <= mid) update(ql,qr,l,mid,lc,x);
    if(mid < qr) update(ql,qr,mid + 1,r,rc,x);
    
}
int query(int p,int l,int r,int rt)
{
    if(l == r) return tr[rt];
    pushdown(l, r, rt);
    if(p <= mid) return query(p, l, mid, lc);
    return query(p, mid + 1, r, rc);
}
int main()
{
    int T;scanf("%d",&T);
    int n;
    while(T --){
        scanf("%d",&n);
        
        mp.clear();
        memset(vis,0,sizeof(vis));
        for(int i = 1;i <= n;i ++){
            scanf("%d%d",&ns[i].l,&ns[i].r);
            //   if(ns[i].l > ns[i].r || ns[i].l < 1 || ns[i].r > 10000000) continue;
            mp[ns[i].l];mp[ns[i].r];
        }
        it = mp.begin();pit = it;it ++;
        vector<int> v;
        while(it != mp.end()){
            if(it->first - pit->first > 1) v.push_back(pit->first + 1);
            pit = it;it ++;
        }
        for(int i = 0;i < v.size();i ++) mp[v[i]];
        int p = 1;
        it = mp.begin();
        while(it != mp.end()) {it->second = p ++;it ++;}
        N = p ;
        init(1, N, 1);
        //  cout << "N = " << N << endl;
        for(int i = 1;i <= n;i ++){
            ns[i].lid = mp[ns[i].l];
            ns[i].rid = mp[ns[i].r];
            //            printf("%d -> %d\n",ns[i].l,ns[i].lid);
            //            printf("%d -> %d\n",ns[i].r,ns[i].rid);
        }
        for(int i = 1;i <= n;i ++){
            update(ns[i].lid ,ns[i].rid,1,N,1,i);
            // printf("update %d %d \n",ns[i].lid,ns[i].rid);
        }
        for(int i = 1;i <= N;i ++){
            int t = query(i,1,N,1);
            //   printf("at %d c = %d\n",i,t);
            
            vis[t] = 1;
        }
        int ans = 0;
        for(int i = 1;i <= n;i ++) if(vis[i]) ans ++;
        printf("%d\n",ans);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值