码迷,mamicode.com
首页 > 其他好文 > 详细

SCUT - 484 - 平面上的点 - 数据结构

时间:2019-08-12 00:49:26      阅读:99      评论:0      收藏:0      [点我收藏+]

标签:str   main   cut   rank   ++   结构   temp   ret   line   

https://scut.online/p/484

一开始想的是按固定斜率的直线从无穷扫下来,但是一直都WA,不知道是哪里错了还是精度问题?

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int MAXN = 1e5 + 5;

int dcmp(long double x, long double y) {
    if(fabs(x - y) <= 1e-14)
        return 0;
    return x < y ? -1 : 1;
}

int n;
ll q;

int ch[MAXN][2];
int val[MAXN];
int dat[MAXN], siz[MAXN], cnt[MAXN];
int tot, root;

inline void Init() {
    tot = 0;
    root = 0;
}

inline int NewNode(int v) {
    val[++tot] = v, dat[tot] = rand();
    ch[tot][0] = ch[tot][1] = 0;
    siz[tot] = 1, cnt[tot] = 1;
    return tot;
}

inline void PushUp(int id) {
    siz[id] = siz[ch[id][0]] + siz[ch[id][1]] + cnt[id];
}

inline void Rotate(int &id, int d) {
    int temp = ch[id][d ^ 1];
    ch[id][d ^ 1] = ch[temp][d];
    ch[temp][d] = id;
    id = temp;
    PushUp(ch[id][d]), PushUp(id);
}

inline void Insert(int &id, int v) {
    if(!id)
        id = NewNode(v);
    else {
        if(v == val[id])
            ++cnt[id];
        else {
            int d = v < val[id] ? 0 : 1;
            Insert(ch[id][d], v);
            if(dat[id] < dat[ch[id][d]])
                Rotate(id, d ^ 1);
        }
        PushUp(id);
    }
}

//找严格小于v的点的个数
int GetRank(int id, int v) {
    if(!id)
        return 0;
    else {
        if(v == val[id])
            return siz[ch[id][0]];
        else if(v < val[id])
            return GetRank(ch[id][0], v);
        else
            return siz[ch[id][0]] + cnt[id] + GetRank(ch[id][1], v);
    }
}

const ll INF = 1e9;

struct Point {
    long double x, y;
    Point() {}
    Point(long double x, long double y): x(x), y(y) {}

    Point Rotate(long double A) {
        return Point(x * cos(A) - y * sin(A), x * sin(A) + y * cos(A));
    }

    bool operator<(const Point &p)const {
        return (dcmp(x, p.x) != 0) ? (x < p.x) : (y < p.y);
    }


} p[MAXN], p2[MAXN];

int nxt[MAXN];

bool check(ll k) {
    Init();
    long double A = atan2(1.0, 1.0 * k);
    for(int i = 1; i <= n; ++i)
        p2[i] = p[i].Rotate(A);

    //按斜率排序
    sort(p2 + 1, p2 + 1 + n);

    for(int i = 1; i <= n; ++i) {
        p2[i] = p2[i].Rotate(-A);
        p2[i].x = round(p2[i].x);
        p2[i].y = round(p2[i].y);
    }

    ll sum = 0;
    for(int i = 1; i <= n; ++i) {
        int res = GetRank(root, (int)p2[i].x);;
        sum += res;
        if(sum >= q)
            return true;
        Insert(root, (int)p2[i].x);
    }
    return false;
}

ll CASE() {
    scanf("%d%lld", &n, &q);
    long double maxy = -INF, miny = INF;
    for(int i = 1; i <= n; ++i) {
        cin>>p[i].x>>p[i].y;
        //scanf("%lf%lf", &p[i].x, &p[i].y);
        if(p[i].y > maxy)
            maxy = p[i].y;
        if(p[i].y < miny)
            miny = p[i].y;
    }
    ll L = -round(maxy - miny), R = round(maxy - miny), M;
    while(1) {
        M = (L + R) >> 1;
        if(L == M) {
            if(check(L))
                return L;
            if(check(R))
                return R;
            return INF;
        }
        if(check(M))
            R = M;
        else
            L = M + 1;
    }
}

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    int T;
    while(~scanf("%d", &T)) {
        while(T--) {
            ll res = CASE();
            if(res >= INF)
                puts("INF");
            else
                printf("%lld\n", res);
        }
    }
    return 0;
}

事实上枚举斜率之后对式子变形:

\(\frac{y_1-y_2}{x_1-x_2}<=k\)

不妨设x1>x2

\(y_1-y_2<=k(x_1-x_2)\)

即:

\(y_1-kx_1<=y_2-kx_2\)

即满足 \(x1>x2\)\(y_1-kx_1<=y_2-kx_2\) 的数对的个数。lzf大佬说是逆序对,太强了。

平衡树卡过去非常勉强:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int MAXN = 1e5 + 5;

int n;
ll q;

int ch[MAXN][2];
ll val[MAXN];
int dat[MAXN], siz[MAXN], cnt[MAXN];
int tot, root;

inline void Init() {
    tot = 0;
    root = 0;
}

inline int NewNode(ll v) {
    val[++tot] = v, dat[tot] = rand();
    ch[tot][0] = ch[tot][1] = 0;
    siz[tot] = 1, cnt[tot] = 1;
    return tot;
}

inline void PushUp(int id) {
    siz[id] = siz[ch[id][0]] + siz[ch[id][1]] + cnt[id];
}

inline void Rotate(int &id, int d) {
    int temp = ch[id][d ^ 1];
    ch[id][d ^ 1] = ch[temp][d];
    ch[temp][d] = id;
    id = temp;
    PushUp(ch[id][d]), PushUp(id);
}

inline void Insert(int &id, ll v) {
    if(!id)
        id = NewNode(v);
    else {
        if(v == val[id])
            ++cnt[id];
        else {
            int d = v < val[id] ? 0 : 1;
            Insert(ch[id][d], v);
            if(dat[id] < dat[ch[id][d]])
                Rotate(id, d ^ 1);
        }
        PushUp(id);
    }
}

int GetRank(int id, ll v) {
    if(!id)
        return 0;
    else {
        if(v == val[id])
            return siz[ch[id][1]] + cnt[id];
        else if(v < val[id])
            return siz[ch[id][1]] + cnt[id] + GetRank(ch[id][0], v);
        else
            return GetRank(ch[id][1], v);
    }
}

const int INF = 1e9;

struct Point {
    int x, y;
    ll z;
    Point() {}
    Point(int x, int y): x(x), y(y) {}

    bool operator<(const Point &p)const {
        return (x != p.x) ? (x < p.x) : (y < p.y);
    }

} p[MAXN];

bool check(int k) {
    //printf("k=%d\n", k);
    Init();
    for(int i = 1; i <= n; ++i) {
        p[i].z = 1ll * p[i].y - 1ll * k * p[i].x;
        //printf("p[%d].z=%lld%c", i, p[i].z, " \n"[i == n]);
        //printf("p[%d].x=%d%c", i, p[i].x, " \n"[i == n]);
    }
    ll sum = 0;
    for(int i = 1, nxt; i <= n; i = nxt) {
        for(nxt = i + 1; nxt <= n && p[nxt].x == p[i].x; ++nxt);
        for(int j = i; j < nxt; ++j) {
            //int gr = GetRank(root, p[j].z);
            //printf("j=%d ,gr=%d\n", j, gr);
            sum += GetRank(root, p[j].z);
            //printf("sum=%lld\n", sum);
//            if(sum >= q)
//                return true;
        }
        for(int j = i; j < nxt; ++j)
            Insert(root, p[j].z);
    }
    if(sum >= q)
        return true;
    return false;
}

int solve() {
    scanf("%d%lld", &n, &q);
    int maxy = -INF, miny = INF;
    for(int i = 1; i <= n; ++i) {
        scanf("%d%d", &p[i].x, &p[i].y);
        if(p[i].y > maxy)
            maxy = p[i].y;
        if(p[i].y < miny)
            miny = p[i].y;
    }
    sort(p + 1, p + 1 + n);
    /*for(int i = 1; i <= n; ++i) {
       //p[i].z = 1ll * p[i].y - 1ll * k * p[i].x;
       //printf("p[%d].z=%lld%c", i, p[i].z, " \n"[i == n]);
       printf("p[%d].x=%d%c", i, p[i].x, " \n"[i == n]);
    }*/
    int L = -(maxy - miny), R = maxy - miny, M;
    while(1) {
        M = (L + R) >> 1;
        if(L == M) {
            if(check(L))
                return L;
            if(check(R))
                return R;
            return INF;
        }
        if(check(M))
            R = M;
        else
            L = M + 1;
    }
}

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    int T;
    while(~scanf("%d", &T)) {
        while(T--) {
            int res = solve();
            if(res >= INF)
                puts("INF");
            else
                printf("%d\n", res);
        }
    }
    return 0;
}

SCUT - 484 - 平面上的点 - 数据结构

标签:str   main   cut   rank   ++   结构   temp   ret   line   

原文地址:https://www.cnblogs.com/Yinku/p/11337258.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!