关于数据结构:归并排序以及二分法

42次阅读

共计 2906 个字符,预计需要花费 8 分钟才能阅读完成。

二分法咱们都晓得,二分的根本过程如下(_merge()见下):

//void erfen(int l,int r){// 二分递归之后归并 
//    int mid;
//    mid = (l + r) / 2;
//    if(l < r){//        erfen(l,mid);
//        erfen(mid + 1,r);
//    }
//    _merge(l,mid,r);
//}

Points in Segments(二分分治)

Given n points (1 dimensional) and q segments, you have to find the number of points that lie in each of the segments. A point pi will lie in a segment A B if A ≤ pi ≤ B.

For example if the points are 1, 4, 6, 8, 10. And the segment is 0 to 5. Then there are 2 points that lie in the segment.

Input
Input starts with an integer T (≤ 5), denoting the number of test cases.

Each case starts with a line containing two integers n (1 ≤ n ≤ 105) and q (1 ≤ q ≤ 50000). The next line contains n space separated integers denoting the points in ascending order. All the integers are distinct and each of them range in [0, 108].

Each of the next q lines contains two integers Ak Bk (0 ≤ Ak ≤ Bk ≤ 108) denoting a segment.

Output
For each case, print the case number in a single line. Then for each segment, print the number of points that lie in that segment.

Sample
Input Output
1
5 3
1 4 6 8 10
0 5
6 10
7 100000

Case 1:
2
3
2

#include<iostream>
#include<algorithm>
#include<string>
#include<string.h>
#include<cstdio>
#include<queue>
#include<stack> 
#include<set> 
#include<vector> 
using namespace std;
/*
lower_bound(begin,end,num):从数组的 begin 地位到 end- 1 地位二分查找第一个大于或等于 num 的数字,找到返回该数字的地址,不存在则返回 end。通过返回的地址减去起始地址 begin, 失去找到数字在数组中的下标。upper_bound(begin,end,num):从数组的 begin 地位到 end- 1 地位二分查找第一个大于 num 的数字,找到返回该数字的地址,不存在则返回 end。通过返回的地址减去起始地址 begin, 失去找到数字在数组中的下标。*/
int a[100010];
int main(){
    int t = 0;
    scanf("%d",&t);
    for(int i = 1; i <= t; i++){
        int n1,n2;
        scanf("%d %d",&n1,&n2);
//        int a[100010];
        for(int j = 0; j < n1; j++){scanf("%d",&a[j]);
        }
        printf("Case %d:\n",i);
        while(n2--){
            int q1,q2,ans1,ans2;
            scanf("%d %d",&q1,&q2);
            ans1 = (int)(upper_bound(a,a + n1,q2) - a);// 最大值处用 upper_bound 必须找到比他大的那个地位 
//            ans1 = (int)(lower_bound(a,a + n1,q2) - a);
            ans2 = (int)(lower_bound(a,a + n1,q1) - a);// 最小值处用 lower_bound 就能够,找到等于他的的那个地位就能够 
            printf("%d\n",ans1 - ans2);
        }
    }
    return 0;
}

逆序对个数(归并排序)

给出一个数组 a,问这个数组中有多少个逆序对。
逆序对定义:若 i <j 且 a[i]>a[j], 则 (a[i]​,a[j]​) 是一个逆序对。
如数组 3 4 1 2 中的逆序对有 (3,1),(3,2),(4,1),(4,2),共 4 个逆序对。
Input
第一行一个整数 n,示意元素个数。
第二行 n 个空格分隔的整数 a[i]。
Output
一个数,示意逆序对个数。
Sample Input 1
5
3 3 4 1 2
Sample Output 1
6
Hint
50% 的数据 n ≤ 6000.
————————————————
参考自 https://blog.csdn.net/qq_4464…

//#include<iostream>
//#include<algorithm>
//#include<string>
//#include<string.h>
//#include<cstdio>
//#include<queue>
//#include<stack> 
//#include<set> 
//#include<vector> 
//using namespace std;
//int a[100010],b[100010];
//long long n,ans;
//void _merge(int l,int mid,int r){// 归并排序代码 
//    int p1,p2;
//    p1 = l;
//    p2 = mid + 1;
//    for(int i = l; i <= r; i++){//        b[i] = a[i];
//    }
//    int x;
//    for(x = p1; p1 <= mid && p2 <= r; x++){//        if(b[p1] > b[p2]){
//            ans += mid - p1 + 1;// 计算逆序数对数 
//            // 参考 https://blog.csdn.net/qq_44643644/article/details/105880856
//            a[x] = b[p2++];
////            cout << ans << x << endl;
//        }else{//            a[x] = b[p1++];
//        }
//    }
//    while(p1 <= mid){// 前半表未取完,持续 
//        a[x++] = b[p1++];
//    }
//    while(p2 <= mid){// 后半表未取完,持续
//        a[x++] = b[p2++];
//    }    
//} 
//void erfen(int l,int r){// 二分递归之后归并 
//    int mid;
//    mid = (l + r) / 2;
//    if(l < r){//        erfen(l,mid);
//        erfen(mid + 1,r);
//    }
//    _merge(l,mid,r);
//}
//int main(){//    scanf("%lld",&n);
//    for(int i = 1; i <= n; i++){//        scanf("%d",&a[i]);
//    }
//    erfen(1,n);
//    printf("%lld\n",ans);
//    return 0;
//}

正文完
 0