poj2528_线段树+离散化

题目描述:

   几张海报有不同的覆盖范围,按先后顺序铺盖上去,看最终在顶层能看到多少张不同的海报。

 

解题思路:

   线段树——还是建树+修改+查询的基本操作。不过费了一天啊。。。有几个需要注意的地方,会容易出现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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值