题目:http://acm.hust.edu.cn/vjudge/problem/14608
题意:好多人在一个宽度固定的公告栏上张贴公告,由于公告张贴先后问题,前面张贴的公告可能会被后面张贴的公告完全覆盖住,现在问你有多少公告没有被完全覆盖。
题解:
先将所给区间离散化,这样就转化为了基本线段树问题。只要一步步区间分解,看是否有地方未被盖住即可。(先从最后贴的开始考虑,这样前面的只需考虑有没有地方未被盖住就好了)。
思考:
1、这道题由于墙的宽度过大,如果按照墙的宽度开数组会MLE,所以要利用离散化。
2、两个都要进行,所以要分别写,不能直接||,如果直接或后面的可能就不会运算
3、unique(num,mun+n)返回的是num去重后的尾地址,好神奇,相当于数组前面元素已经全都不一样了(注意要先排序,因为只删除相邻的相同元素)
4、如果两个端点中间有区间,则那个区间也要标号,因为那个区间也会关系到一个海报能不能露出
5、如果下面的两个区间都被完全覆盖,则此区间也被完全覆盖,这个别忘
#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <queue>
using namespace std;
struct poster{
int l, r;
};
struct CNode{
int l, r;
bool becovered;
int Mid(){
return (l + r) / 2;
}
};
const int maxn = 40005 * 4;
CNode tree[maxn];
poster pos[maxn];
int x[maxn];
int hash1[10000010];//用哈希表存储离散化以后的各区间边界的值
void BuildTree(int root, int l, int r)
{
tree[root].l = l;
tree[root].r = r;
tree[root].becovered = false;
if (l != r) {
BuildTree (2 * root + 1, l, tree[root].Mid());
BuildTree (2 * root + 2, tree[root].Mid() + 1, r);
}
}
bool post(int root, int s, int e)
{
if (tree[root].becovered) return false;
if (tree[root].l == s && tree[root].r == e) {
tree[root].becovered = true;
//printf ("%d %d\n", s, e);
return true;
}
bool bResult;
if (e <= tree[root].Mid()) bResult = post (2 * root + 1, s, e);
else if (s > tree[root].Mid()) bResult = post (2 * root + 2, s, e);
else {
bool b1 = post (2 * root + 1, s, tree[root].Mid());//两个都要进行,所以要分别写,不能直接||,如果直接或后面的可能就不会运算
bool b2 = post (2 * root + 2, tree[root].Mid() + 1, e);
bResult = b1 || b2;
}
if (tree[2 * root + 1].becovered && tree[2 * root + 2].becovered) {//如果下面的两个区间都被完全覆盖,则此区间也被完全覆盖,这个别忘,套路?
tree[root].becovered = true;
}
return bResult;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen ("in.txt", "r", stdin);
#endif // ONLINE_JUDGE
int t, n, num, now;
scanf ("%d", &t);
while (t--) {
num = 0, now = 0;
scanf ("%d", &n);
for (int i = 0; i < n; i++) {
int l, r;
scanf ("%d%d", &l, &r);
x[now++] = l;
x[now++] = r;
pos[i].l = l;
pos[i].r = r;
}
sort (x, x + now);
int xcount = unique (x, x + now) - x;//unique(num,mun+n)返回的是num去重后的尾地址,好神奇,相当于数组前面元素已经全都不一样了(注意要先排序,因为只删除相邻的相同元素)
//离散化开始(把现有区间转化,转化完就是基本的线段树问题)
int nowh = 0;
for (int i = 0; i < xcount; i++) {
hash1[x[i]] = nowh;
if (i < xcount - 1) {//如果两个端点中间有区间,则那个区间也要标号,因为那个区间也会关系到一个海报能不能露出
if (x[i + 1] - x[i] == 1) {
nowh++;
} else {
nowh += 2;
}
}
}
BuildTree (0, 0, nowh);
for (int i = n - 1; i >= 0; i--) {
//printf ("x%d y%d\nh%d %d\n", pos[i].l, pos[i].r, hash1[pos[i].l], hash1[pos[i].r]);
if (post (0, hash1[pos[i].l], hash1[pos[i].r])) {
num++;
}
}
printf ("%d\n", num);
}
return 0;
}