题目大意:有一面一千万长的墙,往墙上贴海报,海报的宽度给出。问最后一共能看到几面海报。
第一反应必然是线段树,但是一千万的线段树必然超内存,所以要离散化。因为我们其实只需要用到海报开始和结束的那两个位置。
这道题的难点在于如何离散化。
如果按照每个点来离散,会出现问题。就用其他题解给出的例子:
如(1,10),(1,4),(6,10)。离散完就是1234四个叶子结点。
那么更新(1,4)时,1-2这段区间被覆盖,更新(6,10)时,3-4区间被覆盖。那么最后查询的时候会发现(1,10)被完全覆盖了。但是,事实上,应该有(5,5)这个区间没有被覆盖。
那么如何解决呢?
搜了网上的题解,说在x相差大于1时加入一个中间节点。在我看来,这就是一坨屎。
我的方法是,参考扫描线解题的过程。因为海报覆盖的是一个个点,我们把点变为块然后离散到数轴上,那么每一个点x都可以变为一段区间(x,x+1)。那么线段树存取什么呢,存取的是一段段区间。就拿上述例子来说,用我的离散方法,数轴被划分为1,5,6,11四个点。那么在线段树内就有三个叶子结点:(1,5)(5,6)(6,11)这样三个区间。这样就完美的解决了中间的5被覆盖的问题。
下面给出代码:
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
#define lc n << 1
#define rc n << 1 | 1
const int maxp = 100005;//注意,用10005还是会数组超界,多开十倍即可
struct segtree {
int l, r, id, lazy;//lazy表示这一段被染过色了
int lx, rx;
bool u;//u表示这个节点的子节点需不需要更新
}t[maxp << 3];
struct flag {
int l, r;
}f[maxp];
int x[maxp << 2];
bool cs[maxp];
inline int getlen(int n) { return t[n].r - t[n].l + 1; }
inline void push_down(int n)
{
t[lc].lazy = t[n].lazy;
t[rc].lazy = t[n].lazy;
t[lc].id = t[n].lazy;
t[rc].id = t[n].lazy;
t[lc].u = t[rc].u = true;
t[n].u = false;
}
void build(int n,int l, int r)
{
t[n].l = l, t[n].r = r;t[n].lazy = 1;t[n].u = false;
t[n].lx = x[l], t[n].rx = x[r];
t[n].id = 0;
if (l + 1 == r) { return; }
int mid = (l + r) >> 1;
build(lc, l, mid);
build(rc, mid, r);
}
void update(int n, int l, int r, int a)
{
if (l > t[n].rx || r < t[n].lx)return;
if (l <= t[n].lx && r >= t[n].rx)
{
t[n].lazy = a;t[n].u = true;
t[n].id = a;
return;
}
if(t[n].u)
push_down(n);
update(lc, l, r, a);
update(rc, l, r, a);
}
int query(int n, int l, int r)
{
if (l > t[n].rx || r < t[n].lx)return 0;
if (l == t[n].lx && r == t[n].rx)
return t[n].id;
if(t[n].u)
push_down(n);
if (r <= t[lc].rx)return query(lc, l, r);
if (l >= t[rc].lx)return query(rc, l, r);
}
int main()
{
int T, n, q, l, r, temp;
cin >> T;
for (int C = 1;C <= T;C++)
{
setLX;
memset(x, 0, sizeof x);
memset(cs, 0, sizeof cs);
memset(t, 0, sizeof t);
cin >> n;q = 0;
for (int i = 1;i <= n;i++)
{
scanf("%d%d", &l, &r);
f[i].l = l;f[i].r = r + 1;
if (!LX.count(l))//这里使用set为了使区间不出现(x,x)这样的无意义区间
{
x[++q] = l;
LX.insert(l);
}
if (!LX.count(r + 1))
{
x[++q] = r + 1;
LX.insert(r + 1);
}
}
sort(x + 1, x + q + 1);
build(1, 1, q);
for (int i = 1;i <= n;i++)
update(1, f[i].l, f[i].r, i);
int ans = 0;
for (int i = 1;i < q;i++)
{
temp = query(1, x[i], x[i + 1]);
if (cs[temp]||!temp)continue;
cs[temp] = true;
ans++;
}
cout << ans << endl;
}
return 0;
}