題目鏈接: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