[luogu4479][BJWC2018]第k大斜率二维偏序+二分+离散化+树状数组

Posted chhokmah

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[luogu4479][BJWC2018]第k大斜率二维偏序+二分+离散化+树状数组相关的知识,希望对你有一定的参考价值。

传送门

https://www.luogu.org/problemnew/show/P4479

题目描述

在平面直角坐标系上,有 n 个不同的点。任意两个不同的点确定了一条直线。请求出所有斜率存在的直线按斜率从大到小排序后,第 k 条直线的斜率为多少。
为了避免精度误差,请输出斜率向下取整后的结果。(例如: ?1.5? = 1 , ??1.5? = ?2 )

分析

一开始打了一个暴力,10分后来改着改着成了30分,浮点误差。
正解其实很简单,我们首先逆向思考一下,如果我们假设已经有了斜率k。
如果两个点之间需要斜率大于k,并且假设我们已经排好了关于x横坐标的序(递增),那么一定会有一个(frac{y_j-y_i}{x_j-x_i}>k)
那么进一步拆开式子最终得到(y_j-kx_j>y_j-kx_j),那么就变成了一个二维偏序,那么离散化+二分k+树状数组求解二维偏序就可以了。

ac代码

#include <bits/stdc++.h>
#define ll long long
#define db double 
#define ms(a, b) memset(a, b, sizeof(a))
#define inf 0x3f3f3f3f
using namespace std;
template <typename T>
inline void read(T &x) {
    x = 0; T fl = 1;
    char ch = 0;
    while (ch < '0' || ch > '9') {
        if (ch == '-') fl = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    x *= fl;
}
#define N 100005
struct data {
    ll x, y, id, val;
    bool operator <(const data &rhs) const {
        return val == rhs.val ? x < rhs.x : val < rhs.val;
    }
}a[N];
struct BIT {
    #define lowbit(x) (x&-x)
    ll tr[N];
    int n;
    void init(int nn) {
        ms(tr, 0);
        n = nn;
    }
    void add(int x, int val) {
        for (; x <= n; x += lowbit(x)) tr[x] += val;
    }
    ll query(int x) {
        ll res = 0;
        for (; x; x -= lowbit(x)) res += tr[x];
        return res; 
    }
}tr;
int n;
int disc_x[N];
ll k;
bool check(int x) {
    for (int i = 1; i <= n; i ++) {
        a[i].val = a[i].y - 1ll * x * a[i].x;
    }
    sort(a + 1, a + 1 + n);
    tr.init(n);
    ll ans = 0;
    for (int i = 1; i <= n; i ++) {
        ans += tr.query(a[i].id - 1);
        tr.add(a[i].id, 1);
    }
    return ans >= k;
}
int main() {
    read(n); read(k);
    for (int i = 1; i <= n; i ++) {
        read(a[i].x); read(a[i].y);
        disc_x[i] = a[i].x;
    }
    sort(disc_x + 1, disc_x + 1 + n);
    int disc_tot = unique(disc_x + 1, disc_x + 1 + n) - disc_x - 1;
    for (int i = 1; i <= n; i ++) {
        a[i].id = lower_bound(disc_x + 1, disc_x + 1 + disc_tot, a[i].x) - disc_x;
    }
    int l = -inf, r = inf, ans;
    while (l <= r) {
        int mid = (l + r) >> 1;
        if (check(mid)) l = mid + 1, ans = mid;
        else r = mid - 1;
    }
    printf("%d
", ans);
    return 0;
}

以上是关于[luogu4479][BJWC2018]第k大斜率二维偏序+二分+离散化+树状数组的主要内容,如果未能解决你的问题,请参考以下文章

Luogu P4482 [BJWC2018]Border 的四种求法

Luogu P4482 [BJWC2018]Border 的四种求法

[luogu4478 BJWC2018] 上学路线 (容斥原理+拓展lucas)

luogu_P4822 [BJWC2012]冻结

BZOJ1229 & 洛谷2917:[USACO2008 NOV]toy 玩具 & 洛谷4480:[BJWC2018]餐巾计划问题——题解

Luogu P4570 [BJWC2011]元素