//poj2528贴海报(线段树离散化)
#include
#include
#include
#include
using namespace std;
const int maxn=100005; //要开10倍的数组,否则RE
bool hash[maxn];
int li[maxn],ri[maxn];
int cov[maxn<<4];
int a[maxn*3];
int cnt;
int BinSea(int key,int n) //二分查找所在的编号即离散后的位置号
{
int l=0,r=n-1;
while(l<=r){
int mid=(l+r)/2;
if(a[mid]==key) return mid;
else if(a[mid]=r){
cov[p]=c;
return;
}
Pushdown(p);
int mid=(l+r)/2;
if(x<=mid) Update(p<<1,l,mid,x,y,c);
if(y>mid) Update(p<<1|1,mid+1,r,x,y,c);
}
void Query(int p,int l,int r) //遍历每个区间的颜色
{
if(cov[p]!=-1){
if(!hash[cov[p]]){
//cout<0;i--) //距离大于1的点之间加一个数
{
if((a[i]-a[i-1])>1) a[h++]=a[i-1]+1;
}
sort(a,a+h);
memset(cov,-1,sizeof(cov));//初始标记为-1
for(int i=0;i
int binsea(int key,int n){
int l=0,h=r-1;
while(l<=r){
int mid=(h+l)>>1;
if(a[mid]==key) return mid;
if(a[mid>key]) l=mid+1;
else if(a[mid]<=key) r=mid-1;
}
return -1;
}
void down(int rt){
if(lazy[rt]!=-1){
lazr[rt<<1]=lazy[rt<<1|1]=laz[rt];
lazy[rt]=-1;
}
}
void update(int rt,int l,int r,int x,int y,int c){// Update(1,0,h-1,l,r,i); c是颜色种类
if(x<=l&&r<=y){//[l,r]属于[x,y]区间 覆盖掉[l,r]区间 [x,y]是题目给的
lazy[rt]=c;return;
}
down(rt);
int mid=(l+r)/2;
if(x<=mid) Update(p<<1,l,mid,x,y,c);
if(y>mid) Update(p<<1|1,mid+1,r,x,y,c);
}
void query(int rt,int l,int r){//query(1,0,h-1)
if(lazy[rt]!=-1){
if(hash[lazy[rt]]==false){//初始值是false 避免重复计数
cnt++;
hash[lazy[rt]]==true;
}
return;
}
if(l==r) return;
int mid=(l+r)/2;
Query(p<<1,l,mid);
Query(p<<1|1,mid+1,r);
}
这道题与之前的题目相比重点在于一个映射的预处理,题目所给的区间达到10000000,而最多只有10000个点,如果直接建树的话太过于空旷。把这些区间的左右节点一一对应,最多有4×10000个点,远小于之前的10000000,而且区间之间的对应关系也不会改变。
举个例子:
区间:[2,6],[4,8],[6,10]
我们进行下面对应:
2 4 6 8 10
1 2 3 4 5
则原区间变为[1,3],[2,4],[3,5]。可以发现它们之间的覆盖关系并没有改变,但是却紧凑了很多。
但是注意对应后,应该有一个去重的操作,防止出错。还有一点去需要注意,区间的对应稍不注意会出现颜色丢失的情况,如下:
[1,10],–[1,4],–[6,10]
当我们手工模拟会发现,我们只是对1,4,6,10,进行了对应,即1,2,3,4,原集合中的4,6被视为了相邻元素,所以5处的颜色丢失,最终得到了错误的结果。
为了防止发生这种情况我们进行插值,在两个不相邻的节点间插入无关值,但是能有效的避免这种情况。