这道题想了挺久的。。。。 TAT
听说POJ这道题的数据奇弱,所以有一种常见的离散方法也是可以过得,但是有错。
转:
**********************************************************************
给出下面两个简单的例子应该能体现普通离散化的缺陷:
例子一:1-10 1-4 5-10
例子二:1-10 1-4 6-10
普通离散化后都变成了[1,4][1,2][3,4]
线段2覆盖了[1,2],线段3覆盖了[3,4],那么线段1是否被完全覆盖掉了呢?
例子一是完全被覆盖掉了,而例子二没有被覆盖
为了解决这种缺陷,我们可以在排序后的数组上加些处理,比如说[1,2,6,10]
如果相邻数字间距大于1的话,在其中加上任意一个数字,比如加成[1,2,3,6,7,10],然后再做线段树就好了
**********************************************************************
(⊙v⊙)嗯,是这样的。
然后之前在纠结的时,肯定用cover[rt]=1表示覆盖,cover[rt]=0表示没有覆盖,cover[rt]=cover[rt<<1]&&cover[rt<<1|1],但是这样有个问题啊,就是我在第二次放线段更新的时候。。。就不能表示叠加啦,,根本不能计算数值的嘛!
所以应该这样!
由于贴广告是不断覆盖的过程,所以我们可以这样考虑,如果从最后一个广告开始update,每次判断的就是能不能进行一次有效的update,(这次贴的广告能不能漏出来),那么任务就可以变成找到一个cover[rt]=0的区间覆盖即可。这样省了好多事啊啊!!
然后在离散的时候要注意,由于每个不相邻的数字间要加塞,所以线段树的范围可能会生生扩大一倍,所以注意maxn。
最后,我发现,,楷体比黑体好看噻!
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
#define maxn 20010
int a[maxn<<1];
map<int,int>mapp;
struct node
{
int l,r;
}que[maxn];
int cover[maxn<<3];
void create(int l,int r,int rt)
{
cover[rt]=0;
if(l==r) return;
int mid=(l+r)>>1;
create(l,mid,rt<<1);
create(mid+1,r,rt<<1|1);
}
int update(int ll,int rr,int l,int r,int rt)
{
if(cover[rt]) return 0;
if(ll==l&&rr==r)
{
cover[rt]=1;
return 1;
}
int mid=(l+r)>>1,ret=0;
if(rr<=mid) ret=update(ll,rr,l,mid,rt<<1);
else if(ll>mid) ret=update(ll,rr,mid+1,r,rt<<1|1);
else
{
ret=update(ll,mid,l,mid,rt<<1);
ret|=update(mid+1,rr,mid+1,r,rt<<1|1);
}
if(cover[rt<<1]&&cover[rt<<1|1])
cover[rt]=1;
return ret;
}
int main()
{
int T;
cin>>T;
while(T--)
{
int n,top=0,ans=0;
cin>>n;
for(int i=0;i<n;i++)
{
int j,k;
cin>>j>>k;
que[i].l=j,que[i].r=k;
a[top++]=j;a[top++]=k;
}
sort(a,a+top);
int count=unique(a,a+top)-a;
int ncount=0;
//create(0,count-1,1);
for(int i=0,j=0;i<count;i++,j++)
{
if(a[i]-1>a[i-1]) j++;
mapp[a[i]]=j;
//printf("map[%d]=%d\n",a[i],j);
ncount=j;
}
create(0,ncount,1);
for(int i=n-1;i>=0;i--)
if(update(mapp[que[i].l],mapp[que[i].r],0,ncount,1))
ans++;
cout<<ans<<endl;
}
return 0;
}