zoukankan      html  css  js  c++  java
  • POJ2104 (平方分割)二分查找理解。

    题意:任意区间求第k大数

    思路:

      预处理:利用平方分割(分桶法)把区间切割成B = sqrt(n)大小的一块块,然后每个各自排序。

      二分第k大数x,接着就需要求[l,r]区间中x的排名,与k比较,将两边端点非完整桶的点进行扫描,最多B次,其余每个桶进行二分查找排名,可利用upper_bound(STL)即可快速实现。

    评价:

      二分确实坑爹,不过搞了这一题也算对二分查找理解深入了些。

    二分正确做法:

    对于[0..n-1)有[0..m]满足性质其余不满足, 则应用[l, r)进行二分查找, 最后l一定是正确的。总是保证l不成立,r成立。

    l = -1, r = n;
    while(l < r-1)
    {
        int mid = (l+r)/2;
        if(check(mid))
            l = mid;
        else
            r = mid;
    }
    cout << l << endl;

    而若是[m, n-1]满足性质, 则应用(l, r]进行二分查找, 最后r一定正确,反之即可。

    保证(l, r]正确性

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <cstdlib>
    #include <cmath>
    #include <utility>
    #include <vector>
    #include <queue>
    #include <map>
    #include <set>
    #define max(x,y) ((x)>(y)?(x):(y))
    #define min(x,y) ((x)>(y)?(y):(x))
    #define INF 0x3f3f3f3f
    #define MAXN 200005
    #define B 1000
    
    using namespace std;
    
    vector<int> bucket[MAXN/B];
    int a[MAXN], q[MAXN], n, m, x, y, k;
    
    int main()
    {
        scanf("%d%d", &n, &m);
        for(int i = 0; i < n; i ++)
        {
            scanf("%d", &a[i]);
            q[i] = a[i];
            bucket[i/B].push_back(a[i]);
        }
        sort(q, q+n);
        for(int i = 0; i < MAXN/B; i ++)
            sort(bucket[i].begin(), bucket[i].end());
        while(m --)
        {
            scanf("%d%d%d", &x, &y, &k);
            x--, y;
            int l = -1, r = n-1; //(l, r]
            while(l < r-1)
            {
                int mid = (l+r)/2;
                int tx = x, ty = y;
                int cnt = 0;
                for( ; tx < ty && tx%B != 0; tx ++)
                    if(a[tx] <= q[mid]) cnt ++;
                for( ; tx < ty && ty%B != 0; ty --)
                    if(a[ty-1] <= q[mid]) cnt ++;
                for(int i = tx/B; i < ty/B; i ++)
                    cnt += upper_bound(bucket[i].begin(), bucket[i].end(), q[mid])-bucket[i].begin();
                if(k <= cnt)
                    r = mid;
                else
                    l = mid;
            }
            if(r < 0)
                printf("-1");
            else
                printf("%d
    ", q[r]);
        }
        return 0;
    }
    View Code

    例如本题若换成[l, r)正确性,稍加改动即可。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <cstdlib>
    #include <cmath>
    #include <utility>
    #include <vector>
    #include <queue>
    #include <map>
    #include <set>
    #define max(x,y) ((x)>(y)?(x):(y))
    #define min(x,y) ((x)>(y)?(y):(x))
    #define INF 0x3f3f3f3f
    #define MAXN 200005
    #define B 1000
    
    using namespace std;
    
    vector<int> bucket[MAXN/B];
    int a[MAXN], q[MAXN], n, m, x, y, k;
    
    int main()
    {
        scanf("%d%d", &n, &m);
        for(int i = 0; i < n; i ++)
        {
            scanf("%d", &a[i]);
            q[i] = a[i];
            bucket[i/B].push_back(a[i]);
        }
        sort(q, q+n);
        for(int i = 0; i < MAXN/B; i ++)
            sort(bucket[i].begin(), bucket[i].end());
        while(m --)
        {
            scanf("%d%d%d", &x, &y, &k);
            x--, y;
            int l = 0, r = n; //[l, r)
            while(l < r-1)
            {
                int mid = (l+r)/2;
                int tx = x, ty = y;
                int cnt = 0;
                for( ; tx < ty && tx%B != 0; tx ++)
                    if(a[tx] < q[mid]) cnt ++;
                for( ; tx < ty && ty%B != 0; ty --)
                    if(a[ty-1] < q[mid]) cnt ++;
                for(int i = tx/B; i < ty/B; i ++)
                    cnt += lower_bound(bucket[i].begin(), bucket[i].end(), q[mid])-bucket[i].begin();
                if(cnt < k)
                    l = mid;
                else
                    r = mid;
            }
            printf("%d
    ", q[l]);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    使用Lua编写Wireshark插件解析KCP UDP包,解析视频RTP包
    开源自己用python封装的一个Windows GUI(UI Automation)自动化工具,支持MFC,Windows Forms,WPF,Metro,Qt
    2019 WebRtc AudioMixer混音流程
    记录一次定位视频通话 音视频卡顿的原因分析过程。
    C++标准库里自带的数值类型和字符串互相转换函数
    C++ raw string literal
    使用multiprocessing解决PyMuPDF不支持多线程加载导致的界面卡死无响应问题,及一个PyQt5实现的简易PDF阅读器例子
    使用ctypes调用系统C API函数需要注意的问题,函数参数中有指针或结构体的情况下最好不要修改argtypes
    使用python uiautomation从钉钉网页版提取公司所有联系人信息
    使用python UIAutomation从QQ2017(v8.9)群界面获取所有群成员详细资料,
  • 原文地址:https://www.cnblogs.com/Mathics/p/4155655.html
Copyright © 2011-2022 走看看