题目链接:http://poj.org/problem?id=2528
类型:线段树+离散化。
本文作者:kuangbin.
转载请注明writed by kuangbin (博客www.cnblogs.com/kuangbin)
这到题目纠结了我一天,主要是离散化,刚接触线段树不是很熟练。
现在对离散化也有点理解了。
离散化 的大概思路 : 比如说给你一组 数据 1 4 1000 100000, 如果直接
开线段, 显然是浪费, 那么我们只要 进行 映射 :
1 1
4 2
1000 3
100000 4
接下来 我们只要对 1 2 3 4 建立线段树就行了 只需要
[1,4]的区间
离散化就相当于是先做映射,然后再建树。
本题大意:给定一些海报,可能相互重叠,告诉你每个海报的宽度(高度都一样的)和先后叠放顺序,问没有被完全盖住的有多少张?
海报最多10000张,但是墙有10000000块瓷砖长,海报不会落在瓷砖中间。
如果直接建树,就算不TLE,也会MLE。即单位区间长度太多。
其实10000张海报,有20000个点,最多有19999个区间。对各个区间编号,就是离散化。然后建数。
其实浮点数也是一样离散化的。
还有好多需要注意的地方。这题的线段树要四倍的,普通的三倍不行了。
细节决定成败:
程序:
/*
HDU 2528 Mayor's posters
本题大意:给定一些海报,可能相互重叠,告诉你每个海报
的宽度(高度都一样的)和先后叠放顺序,问没有被完全盖住的有多少张?
海报最多10000张,但是墙有10000000块瓷砖长,海报不会落在瓷砖中间。
如果直接建树,就算不TLE,也会MLE。即单位区间长度太多。
其实10000张海报,有20000个点,最多有19999个区间。对各个区间编号,就是离散化。然后建数。
其实浮点数也是一样离散化的。
writer:kuangbin
*/
#include<stdio.h>
#include<algorithm>
#include<math.h>
using namespace std;
const int MAXN=10010;
struct Cpost
{
int l,r;
}posters[MAXN];
int x[MAXN*2];
int hash[10000005];
struct Node
{
int l,r;
bool bCovered;//标记是否被完全覆盖
}segTree[MAXN*8];//这里必须开到线段数的四倍,??
void Build(int i,int l,int r)//建立线段树
{
segTree[i].l=l;
segTree[i].r=r;
segTree[i].bCovered=false;
if(l==r)return;
int mid=(l+r)>>1;
Build(i<<1,l,mid);
Build(i<<1|1,mid+1,r);
}
bool Post(int i,int l,int r)//贴上一个好报,同时判断是否被完全覆盖
{
if(segTree[i].bCovered) return false;
if(segTree[i].l==l&&segTree[i].r==r)
{
segTree[i].bCovered=true;
return true;
}
bool bResult;
int mid=(segTree[i].l+segTree[i].r)>>1;
if(r<=mid) bResult=Post(i<<1,l,r);
else if(l>mid)
bResult=Post(i<<1|1,l,r);
else
{
bool b1=Post(i<<1,l,mid);
bool b2=Post(i<<1|1,mid+1,r);
bResult=b1||b2;//不能直接或上去,因为如果前面的真,后面的会不做的
}
//这个很重要,要反馈回原结点,如果左右儿子都被完全覆盖了,自然也完全覆盖了
if(segTree[i<<1].bCovered && segTree[i<<1|1].bCovered)
segTree[i].bCovered=true;
return bResult;
}
int main()
{
int T;
int i,j,k;
int n;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
int nCount=0;
for(i=0;i<n;i++)
{
scanf("%d%d",&posters[i].l,&posters[i].r);
x[nCount++]=posters[i].l;
x[nCount++]=posters[i].r;
}
sort(x,x+nCount);//先排序
nCount=unique(x,x+nCount)-x;//合并掉相同的项
for(i=0;i<nCount;i++)
hash[x[i]]=i;
Build(1,0,nCount-1);
int res=0;
for(i=n-1;i>=0;i--)//要从上面开始看。
if(Post(1,hash[posters[i].l],hash[posters[i].r]))
res++;
printf("%d\n",res);
}
return 0;
}
想了一天,终于解决了这题,对线段树也有了更深的认识。
也明白了离散化的本质。乘胜追击,再做几道线段树来。
by 2011-8-15
文章来源:
http://www.cnblogs.com/kuangbin/archive/2011/08/15/2139931.html