2300: [HAOI2011]防线修建
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 1015 Solved: 558
[ Submit][ Status][ Discuss]
Description
上图中,A,B,C,D,E点为A国城市,且目前都要保护,那么修建的防线就会是A-B-C-D,花费也就是线段AB的长度+线段BC的长度+线段CD的长度,如果,这个时候撤销B点的保护,那么防线变成下图
Input
Output
对于每个询问输出1行,一个实数v,表示修建防线的花费,保留两位小数
Sample Input
2
1 2
3 2
5
2
1 1
2
1 2
2
Sample Output
5.84
4.47
HINT
Source
学了一发动态维护凸包... 所以说算是一个增量法? 每次找到前后趋往两边删, 判断就用叉积判断就行了. 至于前后趋, 插入删除的用个set就好了. 用两个set分别维护上凸壳和下凸壳即可.
这道题只用维护上凸壳就可以了... 还算是十分的好写的. 删除操作不会, 但是发现只有删除操作, 于是可以离线倒过来变成加点操作, 这就很棒棒了...
关于复杂度... 虽然平衡树是log的, 但是每次往两边删... 那我也不会证了(听说凸包上的点数期望很少?
Upd: 突然想起来如果只是增加的话, 那么一个点最多被加入和删除一次!! 均摊nlogn.
还有讲真删除操作怎么搞啊(不离线的话)(实际上又插入又删除也能卡掉离线).
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
int n, m, Q;
double ans;
bool vis[maxn];
inline const int read() {
register int x = 0;
register char ch = getchar();
while (ch < '0' || ch > '9') ch = getchar();
while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x;
}
struct query {
int x, opt; double ans;
}q[maxn];
struct point {
int x, y;
point(){}
point(int x, int y) : x(x), y(y) {}
inline bool operator < (const point &s) const {
return x < s.x || (x == s.x) && y < s.y;
}
inline point operator - (const point &s) const {
return point(x - s.x, y - s.y);
}
inline double operator + (const point &s) const {
return sqrt((double)(x - s.x) * (x - s.x) + (y - s.y) * (y - s.y));
}
inline double operator * (const point &s) const {
return x * s.y - y * s.x;
}
}a[maxn], p1, p2, p3;
set<point> s;
set<point>::iterator l, r, it;
inline void insert(point p) {
r = s.lower_bound(p), l = r;
l --;
if ((*r - *l) * (p - *l) < 0) return;
ans -= (*l) + (*r);
while (true) {
it = r; r ++;
if (r == s.end()) break;
if ((*r - p) * (*it - p) > 0) break;
ans -= (*it) + (*r);
s.erase(it);
}
while (l != s.begin()) {
it = l; l --;
if ((*it - p) * (*l - p) > 0) break;
ans -= (*l) + (*it);
s.erase(it);
}
s.insert(p);
l = r = it = s.find(p);
l --, r ++;
ans += ((*l) + (*it)) + ((*it) + (*r));
}
int main() {
n = read();
p1.x = 0, p1.y = 0, s.insert(p1);
p2.x = n, p2.y = 0, s.insert(p2);
int x = read(), y = read();
p3.x = x, p3.y = y, s.insert(p3);
ans = (p1 + p3) + (p2 + p3);
m = read();
for (int i = 1; i <= m; ++ i) a[i].x = read(), a[i].y = read();
Q = read();
for (int i = 1; i <= Q; ++ i) {
q[i].opt = read();
if (q[i].opt & 1) q[i].x = read(), vis[q[i].x] = true;
}
for (int i = 1; i <= m; ++ i)
if (!vis[i]) insert(a[i]);
for (int i = Q; i; -- i) {
if (q[i].opt & 1) insert(a[q[i].x]);
else q[i].ans = ans;
}
for (int i = 1; i <= Q; ++ i)
if (q[i].opt == 2) printf("%.2f\n", q[i].ans);
return 0;
}