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;
}