题解:
这道题与之前的题目相比重点在于一个映射的预处理,题目所给的区间达到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处的颜色丢失,最终得到了错误的结果。
为了防止发生这种情况我们进行插值,在两个不相邻的节点间插入无关值,但是能有效的避免这种情况。
数组范围分析,10000个区间对应最多20000个节点,再进行插值后得到最多40000+个节点,对应segTree数组达到4×40000+。
而线段树部分实现起来就比较简单了,lazy标记一下,最后统计仍可见的不同颜色就可以了。
代码实现:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define MAX 20010
#define LCHILD root<<1,l,mid
#define RCHILD root<<1|1,mid+1,r
#define MID(x,y) (x+y)>>1
using namespace std;
int T;
int N;
int mm[MAX<<2];
int show[MAX<<3];
int L[MAX],R[MAX];
int segTree[MAX<<3];
void pushdown(int root);
int query(int root,int l,int r,int a,int b);
void update(int root,int l,int r,int a,int b,int flag);
int main(){
scanf("%d",&T);
while( T-- ){
scanf("%d",&N);
int pos = 1;
int tmp = 2;
//注意show[0]要提前标记为1
memset(segTree,0,sizeof(segTree));
memset(show,0,sizeof(show));show[0] = 1;
for( int i = 1; i <= N; i++ ){
scanf("%d%d",&L[i],&R[i]);
mm[pos++] = L[i];
mm[pos++] = R[i];
}
//去重操作
sort(mm+1,mm+pos);
for( int i = 2; i < pos; i++ ){
if( mm[i] != mm[i-1] ){
mm[tmp++] = mm[i];
}
}
//插值
pos = tmp;
for( int i = pos-1; i > 1; i-- ){
if( mm[i] != mm[i-1]+1 ){
mm[pos++] = mm[i-1]+1;
}
}
sort(mm+1,mm+pos);
//lowe_bound找到a,b位置
for( int i = 1; i <= N; i++ ){
int a,b;
a = lower_bound(mm+1,mm+pos,L[i])-mm;
b = lower_bound(mm+1,mm+pos,R[i])-mm;
update(1,1,pos-1,a,b,i);
}
int res = query(1,1,pos-1,1,pos-1);
printf("%d\n",res);
}
return 0;
}
void update(int root,int l,int r,int a,int b,int flag){
if( a > r || b < l ){
return ;
}
if( a <= l && r <= b ){
segTree[root] = flag;
return ;
}
if( segTree[root] != 0 ){
pushdown(root);
}
int mid = MID(l,r);
update(LCHILD,a,b,flag);
update(RCHILD,a,b,flag);
return ;
}
int query(int root,int l,int r,int a,int b){
if( a > r || b < l ){
return 0;
}
//该区间属于同一种颜色,show数组标记是否已被统计
if( segTree[root]!= 0 ){
if( show[segTree[root]] != 1 ){
show[segTree[root]] = 1;
return 1;
}
return 0;
}
//未标色的叶子节点
if( l == r ){
return 0;
}
int mid = MID(l,r);
return query(LCHILD,a,b)+query(RCHILD,a,b);
}
void pushdown(int root){
segTree[root<<1] = segTree[root];
segTree[root<<1|1] = segTree[root];
segTree[root] = 0;
return ;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
POJ_2528 Mayor's poster(线段树+离散化)
时间: 2024-11-08 12:51:48