二分模板
二分不熟悉的可以看一下二分的模板
题目练习
题目描述
达尔星有 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;
}