二分的练习

二分模板

二分不熟悉的可以看一下二分的模板


题目练习


题目描述

达尔星有 n 个强大的下级战士,编号 1∼n。

其中第 i 名战士的战斗力为 ri。

战士 a 可以成为战士 b 的战斗导师,当且仅当 ra>rb 且两人之间不存在矛盾。

给定每个战士的战斗力值以及战士之间存在的 k 对矛盾关系。

请你计算,每个战士可以成为多少战士的战斗导师。

输入格式

第一行包含两个整数 n 和 k。

第二行包含 n 个整数 r1,r2,…,rn。

接下来 k 行,每行包含两个整数 x,y,表示战士 x 和战士 y 之间存在矛盾。同一对矛盾关系不会在输入中重复给出,即出现了 x,y 以后,后面就不会再次出现 x,y 或 y,x。

输出格式

共一行,n 个整数,表示每个战士可以作为战斗导师的战士数量。

数据范围

前三个测试点满足,2≤n≤10,0≤k≤10。
所有测试点满足,2≤n≤2×105,0≤k≤min(2×105,n(n−1)2),1≤ri≤109,1≤x,y≤n,x≠y。

输入样例:

4 2
10 4 10 15
1 2
4 3

输出样例:

0 0 1 2


分析题解

我们发现这个其实是一个较为明显的二分题目。我们先考虑暴力怎么写
暴力是两重循环第一重枚举i个战士,第二重循环枚举除了i的n-1个战士
判断是否能成为战斗导师导师 O ( n 2 ) O(n^2) O(n2)

我们来尝试优化,第一层肯定是无法优化的,关键在于第二重循环,
我们可以 利用二分优化,找出 小于 x i x_i xi​的个数,并减去 有矛盾的个数
一开始 用cnt[N]记录 有矛盾且 r a > r b r_a > r_b ra​>rb​的个数。

代码

#include <bits/stdc++.h>

using namespace std;

const int N = 200010;
int n;
int cnt[N], weight[N], w[N];

int binary(int x)
{
    int l = 1, r = n; 
    
    while (l < r)
    {
        int mid = l + r + 1 >> 1;
        if (w[mid] < x)
            l = mid;
        else 
            r = mid - 1;
    }
    if (w[l] == x)  return 0;	//特判 第一个数左边没有比他小的数 返回0
    return l;
}

int main()
{
    int k;
    cin >> n >> k;
    for (int i = 1; i <= n; i++)   
    {
        cin >> w[i];
        weight[i] = w[i];
    }
    
    sort(w+1,w+1+n);
    
    while (k --)
    {
        int a, b;
        scanf("%d%d", &a,&b);
        if (weight[a] > weight[b])
            cnt[a] ++;
        else if (weight[a] < weight[b])
            cnt[b] ++;
    }
    
    for (int i = 1; i <= n; i ++)
        cout << binary(weight[i]) - cnt[i]  << " ";
    
    
    return 0;
}
上一篇:数据结构与算法---23.prim普利姆算法、kruskal克鲁斯卡尔算法


下一篇:c++背包详解