loj6504. 「雅礼集训 2018 Day5」Convex

时间:2019-12-19
本文章向大家介绍loj6504. 「雅礼集训 2018 Day5」Convex,主要包括loj6504. 「雅礼集训 2018 Day5」Convex使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

题意

给出若干的点,满足每个点都在所有点形成的凸包上,且点\((0, 0)\)在凸包内。
若干次询问一段区间构成凸包的面积。

题解

考虑莫队。
但是发现莫队在加入一个点的时候还要在当前凸包上找前驱和后继,这个复杂度有一个\(\log\),难以优化。
但是删除的时候,我们发现,如果我们维护一个凸包上的点的前驱后继的一个链表,是很方便删除的。
所以需要一个只删除不插入的莫队,这相当于一个回滚莫队。
这个回滚莫队只要有删除操作和撤销操作就好了。由于删除操作比较简单,撤销操作便容易实现。
因此可以在\(\mathcal O(n \sqrt n)\)的时间内解决此题。
顺带复习下回滚莫队:先按左端点所在块排,左端点在同一个块内按照右端点排,每次询问完之后左指针回滚到询问左端点所在块的右边界。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1.5e5 + 10, BLO = 350;
int n, m, id[N], pre[N], suf[N]; ll sum, ans[N];
struct P {
    int x, y;
    bool operator < (const P &o) const {
        return atan2(y, x) < atan2(o.y, o.x);
    }
    ll operator * (const P &o) const {
        return (ll)x * o.y - (ll)o.x * y;
    }
} a[N];
struct Q {
    int l, r, id;
    bool operator < (const Q &o) const {
        return (l - 1) / BLO == (o.l - 1) / BLO ? r > o.r : l < o.l;
    }
} q[N];
bool cmp (int x, int y) {
    return a[x] < a[y];
}
void del (int x) {
    int l = pre[x], r = suf[x];
    sum -= a[l] * a[x] + a[x] * a[r] - a[l] * a[r];
    suf[l] = r, pre[r] = l;
}
void udel (int x) {
    int l = pre[x], r = suf[x];
    sum += a[l] * a[x] + a[x] * a[r] - a[l] * a[r];
    suf[l] = pre[r] = x;
}
int main () {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++i) {
        scanf("%d%d", &a[i].x, &a[i].y), id[i] = i;
    }
    sort(id + 1, id + n + 1, cmp), id[0] = id[n];
    for (int i = 1; i <= n; ++i) {
        pre[id[i]] = id[i - 1], suf[id[i - 1]] = id[i];
        sum += a[id[i - 1]] * a[id[i]];
    }
    for (int i = 1; i <= m; ++i) {
        scanf("%d%d", &q[i].l, &q[i].r), q[i].id = i;
    }
    sort(q + 1, q + m + 1);
    for (int L = 1, R, i = 1, l = 1, r = n; i <= m; L = R + 1) {
        R = min(n, L + BLO - 1);
        for ( ; i <= m && q[i].l <= R; ++i) {
            for ( ; r > q[i].r; del(r--));
            for ( ; l < q[i].l; del(l++));
            ans[q[i].id] = sum;
            for ( ; l > L; udel(--l));
        }
        for ( ; r < n; udel(++r));
        for ( ; l <= R; del(l++));
    }
    for (int i = 1; i <= m; ++i) {
        printf("%lld\n", ans[i]);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/psimonw/p/12066091.html