• 区间查找题解(优先队列+二分)


    Problem:C
    Time Limit:1000ms
    Memory Limit:65535K

    Description

    给定两个长度为 n 的数组 A 和 B,对于所有的 ai+bj 从小到大排序,并输出第 L 个到第 R 个数。

    Input

    第一行三个数 n,L,R。然后分别输入a[i]和b[i];
    

    Output

    输出第L个数到第R个数!

    Sample Input

    2 1 4
    1 3
    2 4
    

    Sample Output

    3 5 5 7 
    注意最后的数后面带1个空格!
    

    Hint

    1<=n<1e5;1<=L<=R<=n^2;R-L<1e5;1<=a[i],b[i]<=1e9;

    思路:

    可以先看看我的另一篇题解:洛谷1631 序列合并(优先队列)_yusen_123的博客-CSDN博客

    n^2个和,可以分成n个序列。

    A[1]+B[1] <= A[1]+B[2] <= … <= A[1]+B[N]

    A[2]+B[1] <= A[2]+B[2] <= … <= A[2]+B[N]

    ……

    A[N]+B[1] <= A[N]+B[2] <= … <= A[N]+B[N]

    二分找大于等于第L-1个相加数的最小数(二分时有个小技巧,可以在o(n)的时间复杂度下求<=x的数有多少)。

    找到大于等于第L-1个相加数的最小数x,统计每个序列<=x有多少个数;找到每个数列>x的第一个数入优先队列

    注意:当第l-1和之后的若干个数相等时,cnt>l-1,我们可以先输出cnt-l+1个x,再更新下l;

    对于每一个序列,我们维护一个最小值,用优先对列,当某一行一个数被输出,我们就让这行下一值进入优先队列。

    代码:

    #define _CRT_SECURE_NO_WARNINGS 
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    using namespace std;
    const int N = 2e5 + 10;
    #define LL long long 
    struct data
    {
        int no;
        int j;
        LL cn;
    }o;
    bool operator > (const struct data& a, const struct data& b)
    {
        return a.cn > b.cn;
    }
    priority_queue, greater > q;
    LL n, L, R, a[N], b[N], to[N];
    LL check(LL x)
    {
        LL cn = n, i = 1;
        LL cnt = 0;
        while (i <= n && cn > 0)
        {
            while (a[i] + b[cn] > x && cn > 0)
                cn--;
            cnt += cn;
            i++;
        }
        return cnt;
    }
    int main()
    {
        cin >> n >> L >> R;
        for (int i = 1; i <= n; i++)
            scanf("%lld", &a[i]);
        for (int i = 1; i <= n; i++)
            scanf("%lld", &b[i]);
        sort(a + 1, a + 1 + n);
        sort(b + 1, b + 1 + n);
        LL l = 0, r = 2e9 + 10, mid, ans;
        while (l <= r)
        {
            mid = (l + r) / 2;
            if (check(mid) >= L - 1)
                r = mid - 1, ans = mid;
            else
                l = mid + 1;
        }
        LL cn = n, cnt = 0;
        for (int i = 1; i <= n; i++)
        {

            while (cn > 0 && a[i] + b[cn] > ans)
                cn--;
            cnt += cn;
            if (cn + 1 <= n)
                q.push({ i,(int)cn + 1,a[i] + b[cn + 1] });
        }
        if (cnt > L - 1)
        {
            for (LL i = L; i <= min(cnt, R); i++)
                printf("%lld ", ans);
            L = cnt + 1;
        }
        cnt = R - L + 1;
        cn = 0;
        while (!q.empty())
        {
            o = q.top();
            q.pop();
            if (cn == cnt)
                break;
            printf("%lld ", o.cn), cn++;
            if (o.j + 1 <= n)
                q.push({ o.no,o.j + 1,a[o.no] + b[o.j + 1] });
        }
        return 0;
    }

  • 相关阅读:
    Redis 主从复制
    【老生谈算法】matlab实现离散系统的时域分析算法源码——离散系统的时域分析
    Python中,类的特殊方法与内置函数的关联
    【课设资源分享】基于jsp的俱乐部会员系统
    PyTorch 深度学习之用PyTorch实现线性回归Linear Regression with PyTorch(四)
    树和森林知识
    java学习part06数组工具类
    RMAN-05021
    SpringBean的实例化
    tomcat多实例部署jenkins
  • 原文地址:https://blog.csdn.net/yusen_123/article/details/133772240