http://poj.org/problem?id=2528
题意:n(n<=10000)个人依次贴海报,给出每张海报所贴的范围li,ri(1<=li<=ri<=10000000)。求出最后还能看见多少张海报。
解法:离散化,如下面的例子(题目的样例),因为单位1是一个单位长度,将下面的
1 2 3 4 6 7 8 10
— — — — — — — —
1 2 3 4 5 6 7 8
离散化 X[1] = 1; X[2] = 2; X[3] = 3; X[4] = 4; X[5] = 6; X[7] = 8; X[8] = 10
于是将一个很大的区间映射到一个较小的区间之中了,然后再对每一张海报依次更新在宽度为1~8的墙上(用线段树),最后统计不同颜色的段数。
但是只是这样简单的离散化是错误的,
如三张海报为:1~10 1~4 6~10
离散化时 X[ 1 ] = 1, X[ 2 ] = 4, X[ 3 ] = 6, X[ 4 ] = 10
第一张海报时:墙的1~4被染为1;
第二张海报时:墙的1~2被染为2,3~4仍为1;
第三张海报时:墙的3~4被染为3,1~2仍为2。
最终,第一张海报就显示被完全覆盖了,于是输出2,但实际上明显不是这样,正确输出为3。
新的离散方法为:在相差大于1的数间加一个数,例如在上面1 4 6 10中间加5(算法中实际上1,4之间,6,10之间都新增了数的)
X[ 1 ] = 1, X[ 2 ] = 4, X[ 3 ] = 5, X[ 4 ] = 6, X[ 5 ] = 10
这样之后,第一次是1~5被染成1;第二次1~2被染成2;第三次4~5被染成3
最终,1~2为2,3为1,4~5为3,于是输出正确结果3。
我是这样理解这个离散化为啥要加中间一个点:如果贴海报只有两个端点很容易出错,但如果中间有一个点会和两个端点有一样的颜色,统计的时候就不会出错(个人想法!!!)
#include
#include
#include
#include
using namespace std;
const int maxn=10100;
#define lson node<<1,l,mid
#define rson node<<1|1,mid+1,r
int x[maxn<<4];
int tree[maxn<<4],ans=0,n=0,num=1;
bool hash[maxn<<2];
int lx[maxn<<2],rx[maxn<<2];
void pushdown(int node)
{
tree[node<<1]=tree[node<<1|1]=tree[node];
tree[node]=-1;
}
void update(int node ,int l,int r,int begin, int end,int x)
{
if(begin<=l&&end>=r)
{
tree[node]=x; return;
}
if(tree[node]!=-1) pushdown(node);
int mid=(l+r)>>1;
if(mid>=begin) update(lson,begin,end,x);
if(mid>1;
query(lson); query(rson);
}
int bsearch(int ll, int rr,int xx)
{
int mm;
while(ll<=rr)
{
mm=(ll+rr)>>1;
if(x[mm]==xx) return mm;
else if(x[mm]>xx) rr=mm-1;
else ll=mm+1;
}
return ll;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(tree,-1,sizeof(tree));
memset(hash,0,sizeof(hash));
int cnt=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&lx[i],&rx[i]);
x[++cnt]=lx[i];
x[++cnt]=rx[i];
}
sort(x+1,x+1+cnt);
num=1;
for(int i=2;i<=cnt;i++)
{
if(x[i]!=x[i-1]) x[++num]=x[i];
}
for(int i=num;i>1;i--)
{
if(x[i]-x[i-1]>1) x[++num]=x[i]-1;
}
sort(x+1,x+1+num);
for(int i=1;i<=n;i++)
{
int l=bsearch(1,num,lx[i]);
int r=bsearch(1,num,rx[i]);
update(1,1,num,l,r,i);
}
ans=0;
query(1,1,num);
printf("%d\n",ans);
}
return 0;
}
个人感觉大佬离散化代码实现写的特别棒 orz!!!
还有一个点 : 原来自己写二分的时候条件 写的是 while(l