题解 CF600B 【Queries about less or equal elements】

TRZ_2007

2020-12-23 17:54:15

Solution

**[题解 CF600B 【Queries about less or equal elements】](https://www.luogu.com.cn/problem/CF600B)** # Solution 观察一下数据,发现 $1\le n,m\le 2\times 10 ^ 5$,因此 $\mathcal{O(n\times m)}$,的暴力做法明显不会过。因此我们考虑**二分**。 ~~如果有同学不会二分呢?~~ 那么……就讲一下吧…… 看这个图: 当然,数据要有序。 ![](https://cdn.luogu.com.cn/upload/image_hosting/7epd1216.png) 我们现在取一下这组数据的中点,发现这个数字大于我们的 mid ,那么在 mid 左边的数字都不可能会是解,因为它们都比 mid 小。继续, ![](https://cdn.luogu.com.cn/upload/image_hosting/5pmueyrj.png) 发现比 mid 大,那么答案在左边,但是区间长度为0了,输出答案就是数字 7 的位置。 但是,我们要的答案不是 7 的位置,而是 5 的位置,怎么办? 减一就好了。 其实用函数也可以,就是比较慢,要吸氧。 听说平衡树或者树状数组也可以过,这里就不讲了。 # Code ```cpp #include <bits/stdc++.h> using namespace std; const int N = 2e5 + 9; struct node { int val,size; int lson,rson; }tree[N * 4]; int n,m,l,r; int a[N],key,ans; inline int find(int key) { l = 1;r = n + 1; int cnt = 0; while(l <= r) { // cout << l << " " << r << "\n"; int mid = (l + r) >> 1; if(a[mid] > key) { cnt = mid; r = mid - 1; } else l = mid + 1; } return cnt; } int main() { scanf("%d %d",&n,&m); for(int i = 1;i <= n;i++) { scanf("%d",&a[i]); } sort(a + 1,a + n + 1); a[n + 1] = INT_MAX; //定义一个哨兵为 inf 以防关键字太大了。 for(int i = 1;i <= m;i++) { scanf("%d",&key); ans = find(key); printf("%d ",ans - 1); } return 0; } ```