线段树3(离散化,连续区间)

题目是依次按给定的范围贴海报,问覆盖到最后还能看到几张海报。

因为给定的贴海报的板子总长度为10^9,数组开不下。但是考虑到海报只有10^5张,而整个问题其实课忽略板子长度,只需要考虑每张海报之间的覆盖关系就可以了,也就是说

(1,1000008)(3,9990)(10,20000000)这三个区间的覆盖情况完全可化成(1,5)(2,4)(3,6),也就是只需要把出现的所有位置进行 排序,把数字转换成对应的序数,这样数组最大 就只需要2*10^5这么大了。另外一个要注意的地方就是海报在区间是连续的,所以节点的意思要改变一下,比如节点左右区间为3和5,离散的区间意思就是3,4,5,这三个点,而连续的区间就是表示(3,5]这段。这样的区别在操作过程中主要体现在结束不再是l==r而应该是r - l <=1,区间分半也不再是(l,m)和(m+1,r)而是(l,m)和(m,r)。



#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <string.h>
#include<string>
#include <math.h>
#include <set>
#include<map>


#define MOD 1000000007;


using namespace std;


struct  node
{
int v;
int l;
int r;
node(int a, int b, int c)
{
v = a;
l = b;
r = c;
lazy = false;
}
node()
{
v = 0;
l = 0;
r = 0;
lazy = false;
}
bool lazy;
};


node ltree[800005];
int z[200005];
int N, Q ,num;
set<int> S;
map<int, int> M;


void creata(int now,int l,int r)
{
ltree[now].l = l;
ltree[now].r = r;
ltree[now].v = 0;
if (l + 1 >= r)
{
return;
}
int m = (l + r >> 1);
creata(now * 2, l, m);
creata(now * 2 + 1, m, r);
return;
}


void find(int now,int l, int r,int v)
{
if (ltree[now].l == l && ltree[now].r == r)
{
ltree[now].lazy = true;
ltree[now].v = v;
return;
}
int m = (ltree[now].l + ltree[now].r >> 1);


if (ltree[now].lazy)
{
ltree[now * 2].lazy = ltree[now * 2 + 1].lazy = true;
ltree[now * 2].v = ltree[now * 2 + 1].v = ltree[now].v;
ltree[now].lazy = false;
}
if (r <= m)
{
find(now * 2, l, r, v);
}
else if (l >= m)
{
find(now * 2 + 1, l, r, v);
}
else
{
find(now * 2, l, m, v);
find(now * 2 + 1, m, r, v);
}




}


void dfs(int now)
{
if (ltree[now].l + 1 >= ltree[now].r)
{
if (ltree[now].v > 0)
S.insert(ltree[now].v);
return;
}
if (ltree[now].lazy)
{
ltree[now * 2].lazy = ltree[now * 2 + 1].lazy = true;
ltree[now * 2].v = ltree[now * 2 + 1].v = ltree[now].v;
ltree[now].lazy = false;
}
dfs(now * 2);
dfs(now * 2 + 1);
}


int main()
{
while (~scanf("%d %d", &N, &Q))
{
S.clear();
M.clear();
for (int i = 1; i <= 2 * N; i = i + 2)
{
scanf("%d %d", &z[i], &z[i + 1]);
S.insert(z[i]);
S.insert(z[i + 1]);
}
num = 0;
for (set<int>::iterator it = S.begin(); it != S.end(); ++it)
{
++num;
M[*it] = num;
}
creata(1, 1, num);
S.clear();
for (int i = 1; i <= 2 * N; i = i + 2)
{
find(1, M[z[i]], M[z[i + 1]], i);
}
dfs(1);
printf("%d\n", S.size());


}
return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值