题目连接:http://poj.org/problem?id=2528
题目大意:在一面墙上贴海报,墙很长,后面贴上去的海报要覆盖掉之前贴上去的海报,现在向墙上逐一的贴海报,问到最后墙上可以看见的海报有几种?
方法:线段树,离散化
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#define maxn 10005
struct node
{
int l, r, d;
}v[maxn<<2];
struct vir
{
int val, pos;
bool operator < (const vir& b)const
{
return val<b.val;
}
}line[maxn<<2];
int set[maxn<<1][2], visited[maxn<<1], ans;
void build(int l, int r, int n)
{
v[n].l = l, v[n].r = r;
v[n].d = -1;
if (l==r)
return ;
int mid = (v[n].l + v[n].r)>>1;
build(l, mid, n<<1);
build(mid+1, r, n<<1|1);
}
void pushdown(int n)
{
if (v[n].d!=-1)
{
v[n<<1].d = v[n].d;
v[n<<1|1].d = v[n].d;
v[n].d = -1;
}
}
void update(int l, int r, int n, int d)
{
if (l<=v[n].l && v[n].r<=r)
{
v[n].d = d;
return ;
}
pushdown(n);
int mid = (v[n].l + v[n].r)>>1;
if (r<=mid)
update(l, r, n<<1, d);
else if (l>mid)
update(l, r, n<<1|1, d);
else
{
update(l, mid, n<<1, d);
update(mid+1, r, n<<1|1, d);
}
}
void find(int l, int r, int n)
{
if (v[n].d>=0 || l==r)
{
if (v[n].d>=0 && !visited[v[n].d])
{
visited[v[n].d] = 1;
++ ans;
}
return ;
}
pushdown(n);
int mid = (v[n].l + v[n].r)>>1;
find(l, mid, n<<1);
find(mid+1, r, n<<1|1);
}
int main()
{
int ncase, n;
cin >> ncase;
while (ncase--)
{
cin >> n;
for (int i=0; i<n; ++i)
{
scanf("%d%d", &set[i][0], &set[i][1]);
line[i<<1].val = set[i][0];
line[i<<1].pos = -(i+1);
line[i<<1|1].val = set[i][1];
line[i<<1|1].pos = i+1;
}
sort(line, line+2*n);
int tp = 1, temp = line[0].val;
for (int i=0; i<2*n; ++i)//离散化
{
if (temp!=line[i].val)
{
++ tp;
temp = line[i].val;
}
if (line[i].pos < 0)
set[ -line[i].pos-1 ][0] = tp;
else
set[ line[i].pos-1 ][1] = tp;
}
build(1, tp, 1);
for (int i=0; i<n; ++i)
update(set[i][0], set[i][1], 1, i);//更新
memset(visited, 0, sizeof(visited));
ans = 0;
find(1, tp, 1);//统计
printf("%d\n", ans);
}
return 0;
}