题目链接:
POJ2528
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 50574 | Accepted: 14658 |
Description
Input
Output
Sample Input
1 5 1 4 2 6 8 10 3 4 7 10
Sample Output
4
题意:
候选者在展览板上贴海报,当所有人都贴完了,有多少海报是可以被看见的(看见,可以是整幅海报都可以被看见,或者是海报的一部分可以被看见)
题解:
我觉得这道题目需要注意的是,(拿样例来说)区间[1,4],1和4不是点(可以看图)是某一块小展览板;
在离散化的时候,需要注意:(看不懂下面的话,可以先看程序,手推一组样例,然后再来理解这段话)
1 3 4 5 9 一般程序对应于 1 2 3 4 5(这样会导致不相邻的线段变为相邻) 实际应该对应于 1 3 4 5 7
线段树+离散化 就OK了
//bei
#include
#include
#include
#include
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define Maxn 12000
int tol[Maxn<<4],segT[Maxn<<4],li[Maxn],ri[Maxn];
//tol是用来保存所有区间的左右端点,segT是建树用的数组,li是保存区间左端点,ri是保存对应右端点
bool vis[Maxn]; //用来标记哪些颜色已经统计过了
int ans;
int Binsearch(int key,int r,int tol[]) //二分查找位置,返回的位置就是离散化后的值
{
int l = 1,m;
while (l <= r)
{
m = (l+r) >> 1;
if (tol[m] > key)
r = m - 1;
else if (tol[m] < key)
l = m + 1;
else
return m;
}
}
void PushDown(int rt) // 线段树的延迟更新
{
if (segT[rt])
{
segT[rt<<1] = segT[rt<<1|1] = segT[rt];
segT[rt] = 0;
}
}
void update(int L,int R,int color,int l,int r,int rt) // 将对应区间的值更新为color,表示该段区间贴的海报
{
if (L <= l && r <= R)
{
segT[rt] = color;
return ;
}
PushDown(rt); // 当该区间被贴上另外的海报时,需要向下更新!
int m = (l+r) >> 1;
if (L <= m)
update(L,R,color,lson);
if (R > m)
update(L,R,color,rson);
}
void query(int l,int r,int rt)
{
if (segT[rt])
// 举个例子:区间[4,6]贴的是同一幅海报,假设对应color的值为2,在线段树中[4,6] 是两段区间[4,5]和[6],当统计完[4,5]之后,再统计到[6]时就不能在加一了
//所以得用一个vis数组用来标记哪些颜色已经被统计过了
{
if (!vis[segT[rt]])
{
++ans;
vis[segT[rt]] = true;
}
return ;
}
if (l == r) return ;
int m = (l+r) >> 1;
query(lson);
query(rson);
}
int main()
{
int c,n,i,k;
while (~scanf("%d",&c))
{
while (c--)
{
scanf("%d",&n);
k = 1;
for (i = 1; i <= n; ++i) // tol数组先保存所有区间的端点值
{
scanf("%d%d",&li[i],&ri[i]);
tol[k++] = li[i];
tol[k++] = ri[i];
}
sort(tol+1,tol+k); // 排序
int m = 2;
for (i = 2; i < k; ++i) // 去掉tol数组中重复的值,因为在二分查找位置时,不能一个值可以映射成两个位置,对吧!
{
if (tol[i] != tol[i-1])
tol[m++] = tol[i];
}
for (i = m - 1; i > 1; --i)//这步+下面的排序一起理解,目的是将原本不相邻的区间也离散成不相邻的区间(可以手推一组样例,就好理解了)
{
if (tol[i] != tol[i-1]+1)
tol[m++] = tol[i-1] + 1;
}
sort(tol+1,tol+m);
memset(segT,0,sizeof(segT));
for (i = 1; i <= n; ++i)
{
int a = Binsearch(li[i],m-1,tol);//得到该区间左端点离散后的值
int b = Binsearch(ri[i],m-1,tol);
update(a,b,i,1,m-1,1);//建树,其中这段区间对应的海报color值为i,正好保证了每幅海报是不相同的
}
ans = 0;
memset(vis,false,sizeof(vis));
query(1,m-1,1); //查询,记得写上上面两条语句;
printf("%d\n",ans);
}
}
return 0;
}