題目鏈接: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個區間。對各個區間編號,就是離散化。然后建數。

其實浮點數也是一樣離散化的。

 

還有好多需要注意的地方。這題的線段樹要四倍的,普通的三倍不行了。

細節決定成?。?/span>

程序:

/*
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