zoukankan      html  css  js  c++  java
  • K-th Number 线段树(归并树)+二分查找

                                K-th Number

    题意:给定一个包含n个不同数的数列a1, a2, ..., an 和m个三元组表示的查询。对于每个查询(i, j, k), 输出ai, ai+1, ... ,aj的升序排列中第k个数 。

    题解:用线段树,每个节点维护一个区间并且保证内部升序,对于每次查询x,返回该区间小于x的数的个数。就这样不断二分,直到找到x为止。

    线段树(归并树)+二分查找

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cmath>
     5 #include <algorithm>
     6 #include <string>
     7 #include <vector>
     8 #include <set>
     9 #include <map>
    10 #include <stack>
    11 #include <queue>
    12 #include <sstream>
    13 #include <iomanip>
    14 using namespace std;
    15 typedef long long LL;
    16 const int INF=0x4fffffff;
    17 const int EXP=1e-5;
    18 const int MS=100005;
    19 
    20 struct node
    21 {
    22       int l,r;
    23       vector<int> vec;
    24 }nodes[4*MS];
    25 
    26 int a[MS];
    27 int num[MS];
    28 int n,m;
    29 
    30 void build(int root,int l,int r)
    31 {
    32       nodes[root].l=l;
    33       nodes[root].r=r;
    34       nodes[root].vec.clear();
    35       if(r-l==1)
    36       {
    37             nodes[root].vec.push_back(a[l]);
    38             return ;
    39       }
    40       int mid=(l+r-1)>>1;
    41       build(root<<1,l,mid+1);
    42       build(root<<1|1,mid+1,r);
    43       nodes[root].vec.resize(r-l);
    44       merge(nodes[root<<1].vec.begin(),nodes[root<<1].vec.end(),
    45            nodes[root<<1|1].vec.begin(),nodes[root<<1|1].vec.end(),nodes[root].vec.begin());
    46 }
    47 
    48 int query(int root,int l,int r,int x)
    49 {
    50       if(r<=nodes[root].l||nodes[root].r<=l)
    51             return 0;
    52       else if(nodes[root].l>=l&&nodes[root].r<=r)
    53             return upper_bound(nodes[root].vec.begin(),nodes[root].vec.end(),x)-nodes[root].vec.begin();
    54       else
    55       {
    56             int lcnt=query(root<<1,l,r,x);
    57             int rcnt=query(root<<1|1,l,r,x);
    58             return lcnt+rcnt;
    59       }
    60 }
    61 
    62 int main()
    63 {
    64       while(scanf("%d%d",&n,&m)!=EOF)
    65       {
    66             for(int i=0;i<n;i++)
    67             {
    68                   scanf("%d",&a[i]);
    69                   num[i]=a[i];
    70             }
    71             sort(num,num+n);
    72             build(1,0,n);
    73             int s,t,k;
    74             for(int i=0;i<m;i++)
    75             {
    76                   scanf("%d%d%d",&s,&t,&k);
    77                   s--;
    78                   int l=-1,r=n-1;
    79                   /*  注意  根据问题特点,这里应该是l=-1,r=n-1.
    80                         如果情况是询问[l,n]这个区间第n-l+1大的值,并且这个值在最后的位置,那么最后的结果会是num[n],越界
    81                         也就是说  二分的结果总是l=mid,知道r-l<=1;         细节问题需要注意
    82                   */
    83                   while(r-l>1)
    84                   {
    85                         int mid=(l+r)>>1;
    86                         int cnt=query(1,s,t,num[mid]);
    87                         if(cnt>=k)
    88                               r=mid;
    89                         else
    90                               l=mid;
    91                   }
    92                   printf("%d
    ",num[r]);
    93             }
    94       }
    95       return 0;
    96 }

    我写的块状数组超时了。不知道是算法真的超时,还是细节问题导致超时。日后再来改正。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <string>
    #include <vector>
    #include <set>
    #include <map>
    #include <stack>
    #include <queue>
    #include <sstream>
    #include <iomanip>
    using namespace std;
    typedef long long LL;
    const int INF=0x4fffffff;
    const int EXP=1e-5;
    const int MS=100005;
    const int SIZE=1000;
    
    int n,m;
    int a[MS];
    int order[MS];
    
    vector<int> bucket[MS/SIZE];
    
    int main()
    {
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            for(int i=0;i<MS/SIZE;i++)
                bucket[i].clear();             // 千万注意清空
            for(int i=0;i<n;i++)
            {
                scanf("%d",&a[i]);
                bucket[i/SIZE].push_back(a[i]);
                order[i]=a[i];
            }
            sort(order,order+n);
            for(int i=0;i<n/SIZE;i++)
                sort(bucket[i].begin(),bucket[i].end());
            int s,t,k;
            while(m--)
            {
                scanf("%d%d%d",&s,&t,&k);
                s--;                         //[s,t)        二分查找使用左必有开更方便一些
                int l=-1,r=n-1;      //   注意:  根据问题的性质,l=0,r=n是错误的,因为有情况总是mid=l,一直到到
                                              //   n-l<=1,  这时答案是num[n],不在给定的数组范围内了。
                while(r-l>1)
                {
                    int mid=(l+r)>>1;
                    int x=order[mid];
                    int tl=s,tr=t,c=0;
                    //  处理区间两端多出的部分
                    while(tl<tr&&tl%SIZE!=0)
                        if(a[tl++]<=x)
                            c++;
                    while(tl<tr&&tr%SIZE!=0)   //  左闭右开  处理方便一些
                        if(a[--tr]<=x)
                            c++;
                    // 对每一个桶进行统计
                    while(tl<tr)
                    {
                        int id=tl/SIZE;
                        c+=upper_bound(bucket[id].begin(),bucket[id].end(),x)-bucket[id].begin();
                        tl+=SIZE;
                    }
                    if(c>=k)
                        r=mid;
                    else
                        l=mid;
                }
                printf("%d
    ",order[r]);
            }
        }
        return 0;
    }

     

  • 相关阅读:
    蜗牛爱课 -- iOS 设计模式之模板模式
    蜗牛爱课- iOS中plist的创建,数据写入与读取
    蜗牛爱课 - iOS7、8模态半透明弹出框
    UIScrollView的属性总结
    简述UITextField的属性和用法
    IOS开发 统计XCODE 代码行数
    当xcode里点运行出现treating unicode character as whites
    Your build settings specify a provisioning profile with the UUID, no such provisioning profile was found的解决方案
    CocoaPods安装和使用教程
    蜗牛爱课- CGAffineTransformMakeRotation 实现一张图片的自动旋转
  • 原文地址:https://www.cnblogs.com/767355675hutaishi/p/4391216.html
Copyright © 2011-2022 走看看