洛谷 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\n", Ans[i]); return 0; }
一步一步,永不停息