1.题目链接。给定一些海报,可能相互重叠,告诉你每个海报的宽度(高度都一样的)和先后叠放顺序,问没有被完全盖住的有多少张?海报最多10000张,但是墙有10000000块瓷砖长,海报不会落在瓷砖中间。
如果直接建树,就算不TLE,也会MLE。即单位区间长度太多。其实10000张海报,有20000个点,最多有19999个区间。对各个区间编号,就是离散化。然后建数。其实浮点数也是一样离散化的。
2.这个题目的离散化其实是很好理解的,但是怎么和线段树联系起来这个似乎有点问题。简单分析一下,假设我们离散化之后,得到了n个点,每张海报其实占据的就是两个点,然后我们就是考察一下这些点组成的线段之间的覆盖关系。对于每张海报的两个点,其实我们把他贴上去,就是在更改这个海报对应的两个点的状态,这些状态指的是:这些点有没有被访问过?被访问了几次?等等。其实我们这里关心的就是这两个点有没有被访问过。这里就涉及到点修改,其实也可以说成区间的修改,我们可以把对点修改看成对差分数组的点修改,对应原数组就是区间修改。然后我们开始贴海报,从后往前贴,为什么,很简单,因为我们最后贴上去的海报是在表面的,所以前边贴上来的有可能被覆盖。其实说多了不是很好,拿起笔自己模拟一下整个程序的流程,就可以清晰的明白代码细节。
#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int MAXN = 10010;
#pragma warning(disable:4996)
struct Cpost
{
int l, r;
}posters[MAXN];
int x[MAXN * 2];
int Hash[10000005];
struct Node
{
int l, r;
bool bcovered;
}seg[MAXN*8];
void build(int n, int l, int r)
{
seg[n].l = l;
seg[n].r = r;
seg[n].bcovered = false;
if (l == r)return;
int mid = (l + r) >> 1;
build(n << 1, l, mid);
build(n << 1 | 1, mid + 1, r);
}
bool post(int n, int l, int r)
{
if (seg[n].bcovered)return false;
if (seg[n].l ==l && seg[n].r == r)
{
seg[n].bcovered = true;
return true;
}
bool bResult;
int mid = (seg[n].l + seg[n].r) >> 1;
if (r <= mid)bResult = post(n << 1, l, r);
else if (l > mid)bResult = post(n << 1 | 1, l, r);
else
{
bool b1 = post(n << 1, l, mid);
bool b2 = post(n << 1 | 1, mid + 1, r);
bResult = b1 || b2;
}
if (seg[n << 1].bcovered&&seg[n << 1 | 1].bcovered)
seg[n].bcovered = true;
return bResult;
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
int n;
scanf("%d", &n);
int cnt = 0;
for (int i = 0; i < n; i++)
{
scanf("%d%d", &posters[i].l, &posters[i].r);
x[cnt++] = posters[i].l;
x[cnt++] = posters[i].r;
}
sort(x, x + cnt);
int ncnt = unique(x, x + cnt) - x;
for (int i = 0; i < ncnt; i++)
Hash[x[i]] = i;
build(1, 0, ncnt - 1);
int res = 0;
for (int i = n - 1; i >= 0; i--)
{
if (post(1, Hash[posters[i].l], Hash[posters[i].r]))
res++;
}
printf("%d\n", res);
}
}