题目描述:
几张海报有不同的覆盖范围,按先后顺序铺盖上去,看最终在顶层能看到多少张不同的海报。
解题思路:
线段树——还是建树+修改+查询的基本操作。不过费了一天啊。。。有几个需要注意的地方,会容易出现MLE,RE或者TLE的。
首先是线段树标记问题,只标记完全覆盖的区间的tab,其余置空以便最后search求出值,目前自己用过的企另外一种标记方式会TLE;然后就是最重要的离散化问题,一开始没有离散化,用3*M的树大小都RE,需要开到4*M,但是开到那个地步又会MLE。而现在算一算,其实只开一个M大小的树就已经超过65535K了。所以必须要进行离散化,即其实这里面有些区间段完全可以用一个单位区间段来表示,即需要对输入的数排序去重后,把区间缩减。这样的话,我们看到总共就输入10000个线段,最多20000个区间段,这样的线段树规模比原先的一千万就小了很多。
代码:
#include
#include
typedef struct {
int l,r;
int tab;
}CH;
CH segTree[70000];
int n, num, flag[20001], tmp_array[20002], array[20002], len, cnt;
int partition(int low, int high){
int tmp = tmp_array[low];
while(low
while(low < high && tmp_array[high] > tmp)
high --;
if(low
tmp_array[low++] = tmp_array[high];
while(low < high && tmp_array[low] < tmp)
low ++;
if(low < high)
tmp_array[high--] = tmp_array[low];
}
tmp_array[low] = tmp;
return low;
}
void quick_sort(int low, int high){
int index;
if(low
index = partition(low, high);
quick_sort(low, index-1);
quick_sort(index+1, high);
}
}
int binaryInsert(int low, int high, int t){ //insert t in array, if not exist then insert, otherwise do not handle. all return the t pos.
int mid = (low+high)/2;
while(low <= high){
if(t == array[mid]){
return mid;
}else if(t < array[mid]){
high = mid - 1;
}else{
low = mid + 1;
}
mid = (low+high)/2;
}
return low;
}
void buildTree(int l, int r, int index){
segTree[index].l = l;
segTree[index].r = r;
segTree[index].tab = 0;
if(l!=r){
buildTree(l,(l+r)/2,2*index);
buildTree((l+r)/2+1,r,2*index+1);
}
}
void changeTree(int l, int r, int index){
if(segTree[index].l == l && r == segTree[index].r){ //恰巧覆盖,则置为顶层标号
segTree[index].tab = num;
//printf("改(%d -> %d)范围值为 %d.\n",l, r, num);
}else{
if(segTree[index].tab != 0){
segTree[2*index].tab = segTree[index].tab;
segTree[2*index+1].tab = segTree[index].tab;
segTree[index].tab = 0;
}
if( l > (segTree[index].l+segTree[index].r)/2 ){ //右区域
// printf("(%d->%d)在右区域\n",l, r);
changeTree(l,r,2*index+1);
}else if( r <= (segTree[index].l+segTree[index].r)/2 ){ //左区域
// printf("(%d->%d)在左区域\n",l, r);
changeTree(l,r,2*index);
}else{ //横跨两个区域
// printf("(%d->%d)跨两个区域\n",l, r);
changeTree(l,(segTree[index].l+segTree[index].r)/2,2*index);
changeTree((segTree[index].l+segTree[index].r)/2+1,r,2*index+1);
}
}
}
void searchTree(int index){
if(segTree[index].tab != 0){
if(flag[segTree[index].tab] != 1){
flag[segTree[index].tab] = 1;
cnt ++;
}
}else{
searchTree(2*index);
searchTree(2*index+1);
}
}
main(){
int i, j, max, x[10001], y[10001], pos;
int test;
scanf("%d",&test);
while(test > 0){
test --;
scanf("%d",&n);
j=1;
for(i=1;i<=n;i++){
scanf("%d %d",&x[i], &y[i]);
tmp_array[j++] = x[i];
tmp_array[j++] = y[i];
}
memset(array,0,sizeof(array));
//做快排后去重
quick_sort(1,2*n); // for tmp_array
array[1] = tmp_array[1];
len = 1;
for(i=2;i<=2*n;i++){// redupliction removing
if(tmp_array[i]!=tmp_array[i-1])
array[++len] = tmp_array[i];
}
//更新值——即所谓的“离散化”
max = 0;
for(i=1;i<=n;i++){
x[i] = binaryInsert(1,len,x[i]);
y[i] = binaryInsert(1,len,y[i]);
if(y[i] > max)
max = y[i];
}
for(i=1;i<=3*max;i++) //清空
segTree[i].tab = 0;
buildTree(1,max,1);
for(num=1;num<=n;num++){ //覆盖满空间则修改tab,否则tab置空 ——
changeTree(x[num],y[num],1);
}
memset(flag,0,sizeof(flag));
cnt = 0;
searchTree(1);
printf("%d\n",cnt);
}
//system("pause");
return 0;
}