求区间第K小值的两种解法:POJ2761

 前几天学习了划分树和SBT,一直没机会训练一下,今天实验室有网了,就训练POJ上面一道水题。分别用两种数据结构来实现了一下!

   这道题题目很简单,就是给定序列,求区间最小值!

   SBT:

 
 
  1. #include<stdio.h> 
  2. #include<algorithm> 
  3. using namespace std; 
  4. #define M 100005 
  5. struct SBT{ 
  6.     int key,left,right,size; 
  7. }tree[M]; 
  8. int root,top; 
  9.  
  10. int a[M]; 
  11. struct Query{ 
  12.     int ql,qr,k,id,ans; 
  13. }que[M/2]; 
  14. bool cmp(const Query &q1,const Query &q2){ 
  15.     if(q1.ql==q2.ql){ 
  16.         return q1.qr<q2.qr; 
  17.     } 
  18.     return q1.ql<q2.ql; 
  19. bool cmp2(const Query &q1,const Query &q2){ 
  20.     return q1.id<q2.id; 
  21. void init(){ 
  22.     root=top=0; 
  23. //这两种旋转看起来是挺容易的,但自己写容易混乱,最好能结合图 
  24. void rotate_left(int &x){ 
  25.     int y=tree[x].right; 
  26.     tree[x].right=tree[y].left; 
  27.     tree[y].left=x; 
  28.     tree[y].size=tree[x].size; 
  29.     tree[x].size=tree[tree[x].left].size+tree[tree[x].right].size+1; 
  30.     x=y; 
  31.  
  32. void rotate_right(int &x){ 
  33.     int y=tree[x].left; 
  34.     tree[x].left=tree[y].right; 
  35.     tree[y].right=x; 
  36.     tree[y].size=tree[x].size; 
  37.     tree[x].size=tree[tree[x].left].size+tree[tree[x].right].size+1; 
  38.     x=y; 
  39. void maintain(int &x,bool flag){ 
  40.     if(flag==false){//数据插入到左边了 
  41.         if(tree[tree[tree[x].left].left].size>tree[tree[x].right].size){//情况 1 
  42.             //左孩子的左子树大于右孩子 
  43.             rotate_right(x); 
  44.         }else if(tree[tree[tree[x].left].right].size>tree[tree[x].right].size){ //情况 2 
  45.             rotate_left(tree[x].left);//先把树旋转成: 情况 1 
  46.             rotate_right(x);//按照情况1进行旋转 
  47.         }else return ; 
  48.     }else{//数据插入到右边了 
  49.         if(tree[tree[tree[x].right].right].size>tree[tree[x].left].size){ 
  50.             rotate_left(x); 
  51.         }else if(tree[tree[tree[x].right].left].size>tree[tree[x].left].size){ 
  52.             rotate_right(tree[x].right); 
  53.             rotate_left(x); 
  54.         }else return ; 
  55.     } 
  56.     maintain(tree[x].left,false); 
  57.     maintain(tree[x].right,true); 
  58.     maintain(x,false); 
  59.     maintain(x,true); 
  60. /* 
  61.  * 这里用数组实现,递归插入,挺巧妙的,我自己用数组做的时候都不会想到这样做 
  62.  * tree的0位置空着不用; 帅气,如果不进行调整的话,root能保持root=1 
  63.  * */ 
  64. void insert(int &x,int key){ 
  65.     if(x==0){ 
  66.         x=++top;//确定插入的数组下标 
  67.         tree[x].left=tree[x].right=0; 
  68.         tree[x].key=key; 
  69.         tree[x].size=1; 
  70.     }else
  71.         tree[x].size++; 
  72.         if(key<=tree[x].key)//把相同的元素插入到左边 
  73.             insert(tree[x].left,key); 
  74.         else insert(tree[x].right,key); 
  75.         maintain(x,key>tree[x].key); 
  76.     } 
  77. //这里要保证删除的数据存在 
  78. void remove(int &x,int key){ 
  79.     tree[x].size--; 
  80.     if(key>tree[x].key){ 
  81.         remove(tree[x].right,key); 
  82.     }else if(key<tree[x].key){ 
  83.         remove(tree[x].left,key); 
  84.     }else
  85.         //有左子树,无右子树 
  86.         if(tree[x].left!=0&&tree[x].right==0){ 
  87.             x=tree[x].left; 
  88.             //无左子树,有右子树 
  89.         }else if(tree[x].right!=0&&tree[x].left==0){ 
  90.             x=tree[x].right; 
  91.         //叶子结点 
  92.         }else if(tree[x].left==0&&tree[x].right==0){ 
  93.             x=0; 
  94.             //有左子树,也有右子树 
  95.         }else
  96.             int temp=tree[x].right; 
  97.             while(tree[temp].left)temp=tree[temp].left; 
  98.             tree[x].key=tree[temp].key; 
  99.             remove(tree[x].right,tree[temp].key); 
  100.         } 
  101.     } 
  102. //求第k小的数 
  103. int select(int &x,int k){ 
  104.     int r=tree[tree[x].left].size+1; 
  105.     if(r==k)return tree[x].key; 
  106.     else if(r<k)return select(tree[x].right,k-r); 
  107.     else return select(tree[x].left,k); 
  108. int main(){ 
  109.     int n,m; 
  110.     int i,j; 
  111.     init(); 
  112.     scanf("%d %d",&n,&m); 
  113.     for(i=1;i<=n;i++){ 
  114.         scanf("%d",&a[i]); 
  115.     } 
  116.     int ql,qr,k; 
  117.     for(i=0;i<m;i++){ 
  118.         scanf("%d %d %d",&ql,&qr,&k); 
  119.         que[i].id=i; 
  120.         que[i].k=k; 
  121.         que[i].ql=ql; 
  122.         que[i].qr=qr; 
  123.     } 
  124.     sort(que,que+m,cmp); 
  125.     for(i=que[0].ql;i<=que[0].qr;i++){ 
  126.         insert(root,a[i]); 
  127.     } 
  128.     que[0].ans=select(root,que[0].k); 
  129.     for(i=1;i<m;i++){ 
  130.         //前一个区间与当前区间只有两种关系,相交或者不相交 
  131.         if(que[i].ql<=que[i-1].qr){ 
  132.             //看起点 
  133.             if(que[i].ql>que[i-1].ql){ 
  134.                 for(j=que[i-1].ql;j<que[i].ql;j++){ 
  135.                     remove(root,a[j]); 
  136.                 } 
  137.             } 
  138.             //看终点 
  139.             if(que[i].qr<que[i-1].qr){// 
  140.                 for(j=que[i].qr+1;j<=que[i-1].qr;j++){ 
  141.                     remove(root,a[j]); 
  142.                 } 
  143.             }else if(que[i].qr>que[i-1].qr){ 
  144.                 for(j=que[i-1].qr+1;j<=que[i].qr;j++){ 
  145.                     insert(root,a[j]); 
  146.                 } 
  147.             } 
  148.         }else
  149.             for(j=que[i-1].ql;j<=que[i-1].qr;j++){ 
  150.                 remove(root,a[j]); 
  151.             } 
  152.             for(j=que[i].ql;j<=que[i].qr;j++){ 
  153.                 insert(root,a[j]); 
  154.             } 
  155.         } 
  156.  
  157.         que[i].ans=select(root,que[i].k); 
  158.     } 
  159.     sort(que,que+m,cmp2); 
  160.     for(i=0;i<m;i++){ 
  161.         printf("%d\n",que[i].ans); 
  162.     } 
  163.     return 0; 

划分树:

 

 
 
  1. #include<stdio.h> 
  2. #include<algorithm> 
  3. using namespace std; 
  4. #define M 100005 
  5. int tree[30][M]; 
  6. int toLeft[30][M]; 
  7. int sorted[M]; 
  8.  
  9. int n,m; 
  10. void build(int level,int left,int right){ 
  11.     if(left==right)return
  12.     int mid=(left+right)>>1; 
  13.     int suppose; 
  14.     int i; 
  15.     suppose=mid-left+1; 
  16.     for(i=left;i<=right;i++){ 
  17.         if(tree[level][i]<sorted[mid]){ 
  18.             suppose--; 
  19.         } 
  20.     } 
  21.     int lpos=left,rpos=mid+1; 
  22.     for(i=left;i<=right;i++){ 
  23.         if(i==left){ 
  24.             toLeft[level][i]=0; 
  25.         }else
  26.             toLeft[level][i]=toLeft[level][i-1]; 
  27.         } 
  28.         if(tree[level][i]<sorted[mid]){ 
  29.             toLeft[level][i]++; 
  30.             tree[level+1][lpos++]=tree[level][i]; 
  31.         }else if(tree[level][i]>sorted[mid]){ 
  32.             tree[level+1][rpos++]=tree[level][i]; 
  33.         }else
  34.             if(suppose){ 
  35.                 suppose--; 
  36.                 toLeft[level][i]++; 
  37.                 tree[level+1][lpos++]=tree[level][i]; 
  38.             }else
  39.                 tree[level+1][rpos++]=tree[level][i]; 
  40.             } 
  41.         } 
  42.     } 
  43.     build(level+1,left,mid); 
  44.     build(level+1,mid+1,right); 
  45. int query(int level,int left,int right,int ql,int qr,int k){ 
  46.     if(ql==qr){ 
  47.         return tree[level][ql]; 
  48.     } 
  49.     int s,ss; 
  50.     int mid=(left+right)>>1; 
  51.     if(left==ql){ 
  52.         s=0; 
  53.         ss=toLeft[level][qr]; 
  54.     }else
  55.         s=toLeft[level][ql-1]; 
  56.         ss=toLeft[level][qr]-s; 
  57.     } 
  58.     int nql,nqr; 
  59.     if(k<=ss){ 
  60.         nql=left+s; 
  61.         nqr=left+s+ss-1; 
  62.         return query(level+1,left,mid,nql,nqr,k); 
  63.     }else
  64.         nql=mid-left+1+ql-s; 
  65.         nqr=mid-left+1+qr-s-ss; 
  66.         return query(level+1,mid+1,right,nql,nqr,k-ss); 
  67.     } 
  68.     return 0; 
  69. int main(){ 
  70.     scanf("%d %d",&n,&m); 
  71.     for(int i=1;i<=n;i++){ 
  72.         scanf("%d",&sorted[i]); 
  73.         tree[0][i]=sorted[i]; 
  74.     } 
  75.     sort(sorted+1,sorted+n+1); 
  76.     build(0,1,n); 
  77.     int ql,qr,k; 
  78.     for(int i=0;i<m;i++){ 
  79.         scanf("%d %d %d",&ql,&qr,&k); 
  80.         int ans=query(0,1,n,ql,qr,k); 
  81.         printf("%d\n",ans); 
  82.     } 
  83.  
  84.     return 0; 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值