题目大意:在墙壁上贴广告,广告的版面有大有小,并且贴广告有先后之分,后面贴的广告会覆盖前面的广告,求解最后能看到的广告面
题目分析
更新的基本原理就是,当我们贴海报i时,如果遇到某一线段区间能够被当前海报完全覆盖,那么我们更新到此区间即可,即让它的颜色更新,记录下新c值。如果不能被海报完全覆盖,则只是这一线段区间的部分区间需要修改,则更改这一区间的子区间的颜色即可。
#include<iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
using namespace std;
struct Node
{
int l; //线段左端点值
int r; //线段右端点
int c; //线段的颜色
}nodes[100000];
int map[30000][2]; //记录输入线段的左右两个端点
int record[30000]; //记录颜色是否已经出现
int total;
struct Line
{
int point; //记录端点的坐标
int num; //记录原来的编号
}line[100000];
int cmp(const Line &a, const Line &b)
{
return a.point < b.point;
}
void build(int l, int r, int p)
{
nodes[p].l = l;
nodes[p].r = r;
nodes[p].c = 0; //初始化颜色都为0
if(l != r)
{
int mid = (l + r) >> 1;
build(l, mid, p<<1); //构造左子树
build(mid + 1, r, p<<1|1); //构造右子树
}
}
void insert(int l, int r, int p, int c)
{
if(nodes[p].l != l || nodes[p].r != r)
{
if(nodes[p].c > 0) //如果当前线段已经有颜色,先将颜色复制给左右两个子树,非常重要
{
nodes[p<<1].c = nodes[p].c;
nodes[p<<1|1].c = nodes[p].c;
nodes[p].c = 0; //标记线段没有颜色
}
if(l >= nodes[p<<1|1].l) //完全在右子树
insert(l, r, p<<1|1, c);
else if(r <= nodes[p<<1].r) //完全在左子树
insert(l, r, p<<1, c);
else //两个子树都有
{
insert(l, nodes[p<<1].r, p<<1, c);
insert(nodes[p<<1|1].l, r, p<<1|1, c);
}
}
else//刚好覆盖,修改颜色,直接返回
{
nodes[p].c = c;
}
}
void update(int p)
{
if(nodes[p].c == 0)
{
//如果当前线段没有颜色,递归调用左右子树,查询颜色
update(p<<1);
update(p<<1|1);
}
//如果当前线段有颜色,记录,并且直接返回
else
{
if(!record[nodes[p].c])
{
total++;
record[nodes[p].c] = 1;
}
}
}
int main()
{
int m;
int n;
int i;
scanf("%d", &m);
while(m--)
{
scanf("%d", &n);
for(i = 0; i < n; i++)
{
scanf("%d%d", &map[i][0], &map[i][1]);
line[2*i].point = map[i][0]; //记录数据,用于离散化
line[2*i + 1].point = map[i][1];
line[2*i].num = -(i + 1); //线段第一个端点用负数记录
line[2*i + 1].num = i + 1; //线段第二个端点用正数记录
}
sort(line, line + 2*n, cmp);
int temp = line[0].point;
int count = 1; //重新开始编号,从1开始
for(i = 0; i < 2*n; i++)
{
if(temp != line[i].point) //如果当前端点和前面的端点不一样,编号值+1
{
count++;
temp = line[i].point;
}
if(line[i].num < 0)
map[-line[i].num - 1][0] = count;
else
map[line[i].num - 1][1] = count;
}
build(1, count, 1);
for(i = 0; i < n; i++)
insert(map[i][0], map[i][1], 1, i + 1);
memset(record, 0, sizeof(record));
total = 0;
update(1);
printf("%d\n", total);
}
return 0;
}