计算几何专题训练

  • 牛客多校10 J Illuminations

点到凸包切点,转换为求环上最少区间进行覆盖

#include <bits/stdc++.h>

using namespace std;
const double eps = 1e-15;

inline static int dcmp(double x) { return x < -eps ? -1 : x > eps ? 1 : 0; }

struct xl {
    double x, y;
    int id;

    xl() {}

    void in() {
        scanf("%lf%lf", &x, &y);
    }

    xl(double x, double y) : x(x), y(y) {}

    xl operator+(const xl &rhs) const { return xl(x + rhs.x, y + rhs.y); }

    xl operator-(const xl &rhs) const { return xl(x - rhs.x, y - rhs.y); }

    xl operator*(const double &rhs) const { return xl(x * rhs, y * rhs); }

    xl operator/(const double &rhs) const { return xl(x / rhs, y / rhs); }
    
    double angle(){return atan2(y,x);}

};
double D_(const xl &a, const xl &b) {
    return a.x * b.x + a.y * b.y;
}

double X_(const xl &a, const xl &b) {
    return a.x * b.y - a.y * b.x;
}

double onleft(xl &a, xl &b, xl &c) {
    return X_(b - a, c - a);
}
 
int n, m;
xl a[400020];
xl b[200020];
xl base;
int you(xl q) {
    int ret = 0;
    int lo = 1, hi = n - 1;
    while (lo <= hi) {
        bool dnl = onleft(q, a[lo + 1], a[lo]) > 0;
        int mid = (lo + hi + 1) >> 1;
        bool dnm = onleft(q, a[mid + 1], a[mid]) > 0;
        if (dnm) {
            if (onleft(q, a[ret], a[mid]) > 0)
                ret = mid;	
        }
        if (dnl) {
            if (onleft(q, a[ret], a[lo]) > 0)
                ret = lo;
            if (dnm && onleft(q, a[lo], a[mid]) > 0)
                hi = mid - 1;
            else lo = mid + 1;
        } else {
            if (!dnm && onleft(q, a[lo], a[mid]) > 0)
                lo = mid + 1;
            else hi = mid - 1;
        }
    }
    return ret == 0 ? n : ret;
}
int zuo(xl q)
{
    int ret = 0;
    int lo = 1, hi = n - 1;
    while (lo <= hi) {
        bool dnl = onleft(q, a[lo - 1], a[lo]) < 0;
        int mid = (lo + hi + 1) >> 1;
        bool dnm = onleft(q, a[mid - 1], a[mid]) < 0;
        if (dnm) {
            if (onleft(q, a[ret], a[mid]) < 0)
                ret = mid;
        }
        if (dnl) {
            if (onleft(q, a[ret], a[lo]) < 0)
                ret = lo;
            if (dnm && onleft(q, a[lo], a[mid]) < 0)
                lo = mid + 1;
            else hi = mid - 1;
        } else {
            if (!dnm && onleft(q, a[lo], a[mid]) < 0)
                hi = mid - 1;
            else lo = mid + 1;
        }
    }
    return ret == 0 ? n : ret;
}
struct wocao {
    int l, r;
    int id;

    wocao() {}

    wocao(int ll, int rr, int iid) {
        if (rr < ll)rr += n;
        l = ll;
        r = rr;
        id = iid;
    }

    bool operator<(const wocao &rhs) const {
        return l == rhs.l ? r > rhs.r : l < rhs.l;
    }
};
wocao q[400020];
int nima[400040][22];
int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++)a[i].in();
    a[0] = a[n];
    base = a[1];
    for (int i = 1; i <= m; i++)
    {
		b[i].in(), b[i].id = i;
		q[i]=wocao(you(b[i]),zuo(b[i]),i);
	}
    sort(q + 1, q + m + 1);
    int Max = 0, ed = 0;
    for (int i = 1; i <= m; i++) {
        if (q[i].r <= Max)continue;
        else {
            Max = q[i].r;
            q[++ed] = q[i];
        }
    }
    m = ed;
    for (int i = 1; i <= m; i++)q[i + m] = wocao(q[i].l + n, q[i].r + n, q[i].id);
    for (int i = 1; i <= m; i++)
        if (q[i + 1].l > q[i].r) {
            puts("-1");
            exit(0);
        }
    if(q[m].r-q[1].l<n)
    {
    	puts("-1");
    	exit(0);
    }
    int now = 1;
    for (int i = 1; i <= 2 * m; i++) {
        while (q[now].l <= q[i].r && now <= 2 * m)now++;
        nima[i][0] = now - 1;
    }
    for (int k = 1; k <= 19; k++) {
        for (int i = 1; i <= 2 * m; i++) {
            nima[i][k] = nima[nima[i][k - 1]][k - 1];
        }
    }
    int ans = m + 1, o;
    for (int i = 1; i <= m; i++) {
        if(q[nima[i][18]].r-q[i].l<n)continue;
        now=i;
        int temp=0;
        for(int j=18;j>=0;j--)
        {
            if(q[nima[now][j]].r-q[i].l<n)
                now=nima[now][j],temp+=1<<j;
        }
        if(temp + 1<ans)ans=temp+1,o=i;
    }
    cout << ans + 1 << "\n";
    now = o;
    for (int i = 0; i <= ans; i++) {
        printf("%d ", q[now].id);
        now = nima[now][0];
    }
    return 0;
}
/*
7
2
0 0
2 1
3 2
4 4
3 6
2 7
0 8

9 4
-1 1

3 4
0 0
1 0
0 1
2 2
-1 3
-1 -1
-0.5 -0.5
*/
  • gym101201 E Enclosure

求在原来凸包的基础上增加一个点的新凸包面积的最大值。
倍增预处理凸包上点\(i\)往后\(1<<k\)个点形成的多边形面积,求出其他点在凸包上的切点\(L,R\),用三角形面积减小多边形面积即是增加的面积。

#include <bits/stdc++.h>

using namespace std;
const double eps = 1e-15;

inline static int dcmp(double x) { return x < -eps ? -1 : x > eps ? 1 : 0; }

struct xl {
    long long x{}, y{};
    int id{};

    xl() {}

    void in() {
        scanf("%lld%lld", &x, &y);
    }

    xl(long long x, long long y) : x(x), y(y) {}

    xl operator+(const xl &rhs) const { return {x + rhs.x, y + rhs.y}; }

    xl operator-(const xl &rhs) const { return {x - rhs.x, y - rhs.y}; }

    bool operator<(const xl &rhs) const {
        return x == rhs.x ? y < rhs.y : x < rhs.x;
    }
};

long long D_(const xl &a, const xl &b) {
    return a.x * b.x + a.y * b.y;
}

long long X_(const xl &a, const xl &b) {
    return a.x * b.y - a.y * b.x;
}

long long onleft(xl &a, xl &b, xl &c) {
    return X_(b - a, c - a);
}

int n, k, blen;
vector<xl> b, c;

int you(xl q) {
    int ret = 0;
    int lo = 1, hi = blen - 1;
    while (lo <= hi) {
        bool dnl = onleft(q, b[lo + 1], b[lo]) > 0;
        int mid = (lo + hi + 1) >> 1;
        bool dnm = onleft(q, b[mid + 1], b[mid]) > 0;
        if (dnm) {
            if (onleft(q, b[ret], b[mid]) > 0)
                ret = mid;
        }
        if (dnl) {
            if (onleft(q, b[ret], b[lo]) > 0)
                ret = lo;
            if (dnm && onleft(q, b[lo], b[mid]) > 0)
                hi = mid - 1;
            else lo = mid + 1;
        } else {
            if (!dnm && onleft(q, b[lo], b[mid]) > 0)
                lo = mid + 1;
            else hi = mid - 1;
        }
    }
    return ret;
}

int zuo(xl q) {
    int ret = 0;
    int lo = 1, hi = blen - 1;
    while (lo <= hi) {
        bool dnl = onleft(q, b[lo - 1], b[lo]) < 0;
        int mid = (lo + hi + 1) >> 1;
        bool dnm = onleft(q, b[mid - 1], b[mid]) < 0;
        if (dnm) {
            if (onleft(q, b[ret], b[mid]) < 0)
                ret = mid;
        }
        if (dnl) {
            if (onleft(q, b[ret], b[lo]) < 0)
                ret = lo;
            if (dnm && onleft(q, b[lo], b[mid]) < 0)
                lo = mid + 1;
            else hi = mid - 1;
        } else {
            if (!dnm && onleft(q, b[lo], b[mid]) < 0)
                hi = mid - 1;
            else lo = mid + 1;
        }
    }
    return ret;
}

xl a[100010];

void hull(vector<xl> &ret, int m) {
    sort(a + 1, a + m + 1);
    int rm = 0;
    for (int i = 1; i <= m; i++) {
        while (rm > 1 && dcmp(X_(ret[rm - 1] - ret[rm - 2], a[i] - ret[rm - 2])) < 0)ret.pop_back(), rm--;
        ret.push_back(a[i]), rm++;
    }
    int kk = rm;
    for (int i = m - 1; i >= 1; i--) {
        while (rm > kk && dcmp(X_(ret[rm - 1] - ret[rm - 2], a[i] - ret[rm - 2])) < 0)ret.pop_back(), rm--;
        ret.push_back(a[i]), rm++;
    }
    if (m > 1)rm--, ret.pop_back();
}

long long area[200010][20];//16
int main() {
    cin >> n >> k;
    for (int i = 1; i <= n; i++)a[i].in();
    hull(b, k);
    blen = b.size();
    for (int i = 0; i < blen; i++)b.push_back(b[i]);
    hull(c, n);
    for (int i = 0; i < 2 * blen; i++)area[i][0] = 0;
    for (int i = 1; i <= 16; i++) {
        for (int j = 0; j < 2 * blen; j++)
            if (j + (1 << i) < 2 * blen) {
                int mid = j + (1 << (i - 1));
                area[j][i] = area[j][i - 1] + area[mid][i - 1] +
                             abs(X_(b[mid] - b[j], b[mid] - b[j + (1 << i)]));
            } else break;
    }
    long long ans = 0;
    for (auto x:c) {
        int l = you(x);
        int r = zuo(x);
        if (l == r)continue;
        long long ar = abs(X_(x - b[l], x - b[r]));
        if (r < l)r += blen;
        int cha = r - l;
        long long temp = 0;
        for (int i = 16; i >= 0; i--)
            if (cha & (1 << i)) {
                int mid = l + (1 << i);
                temp += abs(X_(b[l] - b[mid], b[mid] - b[r])) + area[l][i];
                l = mid;
            }
        ans = max(ans, -temp + ar);
    }
    for (int i = 2; i < blen; i++)
        ans += abs(X_(b[i] - b[i - 1], b[i] - b[0]));
//    for (int i = 0; i < blen; i++)cerr << b[i].x << " " << b[i].y << "\n";
    printf("%lld.%lld", ans / 2, ans % 2 ? 5 : 0);
    return 0;
}

  • codeforces250.D

对每个\(B\),其到原点的线段与左河岸交点为\((aa,\frac{a}{b}y')\),二分找到最近的\(A\)

#include<bits/stdc++.h>

using namespace std;
int n, m, aa, bb, b[100010], l[100010];
double a[100010];
double ans = 10000000000000000000.;
int o1, o2;

double f(double x) { return x * x; }

double dis(double x1, double y1, double x2, double y2) {
    return sqrt(f(x1 - x2) + f(y1 - y2));
}

void upd(int i, int j) {
    double temp = dis(0, 0, aa, a[i]) + dis(aa, a[i], bb, b[j]) + l[j];
    if (temp < ans) {
        ans = temp;
        o1 = i, o2 = j;
    }
}

int main() {
    scanf("%d%d%d%d", &n, &m, &aa, &bb);
    for (int i = 1; i <= n; i++)scanf("%lf", &a[i]);
    sort(a + 1, a + n + 1);
    for (int i = 1; i <= m; i++)scanf("%d", &b[i]);
    for (int i = 1; i <= m; i++)scanf("%d", &l[i]);
    for (int i = 1; i <= m; i++) {
        double x = 1. * b[i] / bb * aa;
        int pos = lower_bound(a + 1, a + n + 1, x) - a;
        if (pos == n + 1)upd(n, i);
        else if (pos == 1)upd(1, i);
        else upd(pos - 1, i), upd(pos, i);
    }
    cout << o1 << " " << o2;
    return 0;
}
posted @ 2021-08-18 16:12  HugeGun  阅读(51)  评论(0编辑  收藏  举报