洛谷 P2521 [HAOI2011]防线修建 (动态凸包,凸包性质 + set)

题目:传送门

题意

 

 

思路

每次询问 1 都是删除 1 个点,由于删除点对凸包的影响比较难搞,所以,我们可以用离线做法,将询问逆着来做,这样,每次询问 1 就相当于加入一个点,加入一个点对凸包的影响,是比较好维护的,可以用 set 存当前凸包的点,具体细节看代码。

#include <bits/stdc++.h>
#define LL long long
#define ULL unsigned long long
#define mem(i, j) memset(i, j, sizeof(i))
#define rep(i, j, k) for(int i = j; i <= k; i++)
#define dep(i, j, k) for(int i = k; i >= j; i--)
#define pb push_back
#define make make_pair
#define INF INT_MAX
#define inf LLONG_MAX
#define PI acos(-1)
#define fir first
#define sec second
using namespace std;

const int N = 1e6 + 5;
const double eps = 1e-10;

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

Point operator + (Point A, Point B) { return Point(A.x + B.x, A.y + B.y); }
Point operator - (Point A, Point B) { return Point(A.x - B.x, A.y - B.y); }
Point operator * (Point A, double p) { return Point(A.x * p, A.y * p); }
Point operator / (Point A, double p) { return Point(A.x / p, A.y / p); }
double Cross(Point A, Point B) { return A.x * B.y - A.y * B.x; }
double Dot(Point A, Point B) { return A.x * B.x + A.y * B.y; }
double Length(Point A) { return sqrt(Dot(A, A)); }

int dcmp(double x) {
    if(fabs(x) < eps) return 0; return x < 0 ? -1 : 1;
}

bool operator < (Point A, Point B) {
    return A.x < B.x || (A.x == B.x && A.y < B.y);
}

double dis(Point A, Point B) { return Length(B - A); }

double ans = 0.0;

Point p[N];

bool vis[N];

double Ans[N];

int id[N], pos[N];

set < Point > Q;

void add(Point tmp) {
    set < Point >::iterator l, r, t;
    l = r = Q.upper_bound(tmp);
    l--;

    if(dcmp(Cross(*r - *l, *r - tmp)) > 0) return ; /// 点在凸包内,即向量 tmp->r 在向量 l->r 的左边

    ans -= dis(*l, *r);

    while(l != Q.begin()) {
        t = l; t--;
        if(dcmp(Cross(*l - tmp, *t - tmp)) > 0) break; /// 满足凸包性质
        ans -= dis(*l, *t);
        Q.erase(*l); l = t;
    }

    while(1) {
        t = r; t++;
        if(t == Q.end() || dcmp(Cross(*t - tmp, *r - tmp)) > 0) break; /// 满足凸包性质
        ans -= dis(*r, *t);
        Q.erase(r); r = t;
    }
    Q.insert(tmp);
    l = r = Q.find(tmp);
    l--; r++;
    ans += dis(tmp, *l) + dis(tmp, *r);
}

int main() {

    int n, m;
    double x, y;
    scanf("%d %lf %lf", &n, &x, &y);
    scanf("%d", &m);

    rep(i, 1, m) scanf("%lf %lf", &p[i].x, &p[i].y);

    Q.insert(Point(0, 0));
    Q.insert(Point(n, 0));
    Q.insert(Point(x, y));

    ans += dis(Point(0, 0), Point(x, y));
    ans += dis(Point(n, 0), Point(x, y));

    int q; scanf("%d", &q);

    rep(i, 1, q) {
        scanf("%d", &id[i]);
        if(id[i] == 1) {
            scanf("%d", &pos[i]);
            vis[pos[i]] = 1;
        }
    }

    rep(i, 1, m) if(!vis[i]) add(p[i]);

    dep(i, 1, q) {
        if(id[i] == 1) add(p[pos[i]]);
        else Ans[i] = ans;
    }

    rep(i, 1, q) if(id[i] == 2) printf("%.2f
", Ans[i]);

    return 0;
}
一步一步,永不停息
原文地址:https://www.cnblogs.com/Willems/p/12563347.html