poj2352_线段树

题目描述:

   给出一个根据星星所处坐标位置来计算星星等级的规则。求位于每个等级的星星的个数。

 

解题思路:

   思路一:不用线段树的话,就是直接计算x坐标序列的序号:即遍历x,计算当前x之前有几个数小于等于自己(二分找),记为当前数所处的level。最后统计一下即可。这个是个线性的查找法,所以复杂度是n平方。

   思路二:用线段树的话,基本思路就是把建立区间树,然后计算的等级等于遍历x序列,修改标签值时累加的左子树的标签和。re了几次,需要注意:线段树不是完全二叉树!比如某个线段树的左子树是[1-7],还有右子树,所以你就能看到左子树的7这个点是没有孩子的,不是完全二叉树。数组大小一定要开够。

 

代码:

线段树——:

#include <stdio.h>
#include <stdlib.h>
#define N 15010
#define TREENUM 32010

typedef struct{
   int l, r;
   int tab;
}CH;

CH segTree[3*TREENUM]; //不是完全二叉树!
int n, min = 32001, max=0, level[N+1],cntLevel[N+1],pos,y,x[N+1];

void buildTree(int index, int l, int r){
   CH ch;
   ch.l = l;
   ch.r = r;
   ch.tab = 0;
   segTree[index] = ch;
   if( l == r )
       ;
   else{
       buildTree(2*index, l,(l+r)/2);
       buildTree(2*index+1, (l+r)/2+1, r);
   }
}

void mark(int num, int index ){
   segTree[index].tab ++;//沿路打标记,表示点落在该范围
   if( segTree[index].l != segTree[index].r){
       if(num <= (segTree[index].l + segTree[index].r)/2){
           mark(num,2*index);
       }else {
           level[pos] += segTree[2*index].tab;//计算级别 += 左子树的点数量
           mark(num,2*index+1);
       }
   }else{
       level[pos] += segTree[index].tab - 1;
   }
}

main(){
   int  i;
   memset(level,0,sizeof(level));
   memset(cntLevel,0,sizeof(cntLevel));
   scanf("%d",&n);
   for(i=1;i<=n;i++){
      scanf("%d %d",&x[i],&y);
      if(x[i] < min)
         min = x[i];
      if(x[i] > max)
         max = x[i];
   }
   for(i=1;i<=n;i++){
      x[i] -= min;
   }
   // [min, max]
   max = max-min;
   min = 0;
   // build tree of [0,max]
   buildTree(1,min,max); // 2*(max+1) - 1 个节点
   // mark tab in segTree
   for(pos=1;pos<=n;pos++){
      mark(x[pos],1);
      //printf("after mark, segtree's tab is:");
//      for(i=1;i<=2*max+1;i++)
//         printf("%d ",segTree[i].tab);
//      printf("\n");
   }
   for(i=1;i<=n;i++){
      cntLevel[level[i]] ++ ;
      //printf("%d为%d级别\n",x[i],level[i]);
   }
   for(i=0;i<n;i++)
      printf("%d\n",cntLevel[i]);
     
  
   //system("pause");
   return 0;
}

非线段树:

#include <stdio.h>
#include <stdlib.h>
#define N 15001

int n,y,x[N],level[N],tag[N], taglen;

int binarySearch(int t){
  
   int low = 0, high = taglen, mid = (low+high)/2;
  
   while(low <= high){
      if( t< tag[mid]){
          high = mid-1;
      }else{
         low = mid + 1;
      }
      mid = (low+high)/2;
   }
   return low;
  
}

main(){
   int i,j,pos;
  
   memset(level,0,sizeof(level));
   scanf("%d",&n);
   for(i=1;i<=n;i++){
      scanf("%d %d",&x[i],&y);
      tag[i] = 32001;
   }
   tag[0] = 32001;

   //find
   taglen = 0;
   for(i=1;i<=n;i++){
      pos = binarySearch(x[i]);
      //printf("pos=%d\n",pos);
      //插入pos 起往后移位
      for(j=taglen-1;j>=pos;j--){
         tag[j+1] = tag[j];
      }
      tag[pos] = x[i];
      taglen ++;
      level[pos]++;
   }
  
   for(i=0;i<n;i++)
      printf("%d\n",level[i]);
                    
  
   //system("pause");
   return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值