[BZOJ]2300 [HAOI2011] 防线修建 动态维护凸包
2018-01-12 10:17
417 查看
2300: [HAOI2011]防线修建
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 1015 Solved: 558
[Submit][Status][Discuss]
Description
近来A国和B国的矛盾激化,为了预防不测,A国准备修建一条长长的防线,当然修建防线的话,肯定要把需要保护的城市修在防线内部了。可是A国上层现在还犹豫不决,到底该把哪些城市作为保护对象呢?又由于A国的经费有限,所以希望你能帮忙完成如下的一个任务:1.给出你所有的A国城市坐标
2.A国上层经过讨论,考虑到经济问题,决定取消对i城市的保护,也就是说i城市不需要在防线内了
3.A国上层询问对于剩下要保护的城市,修建防线的总经费最少是多少
你需要对每次询问作出回答。注意单位1长度的防线花费为1。
A国的地形是这样的,形如下图,x轴是一条河流,相当于一条天然防线,不需要你再修建
A国总是有两个城市在河边,一个点是(0,0),一个点是(n,0),其余所有点的横坐标均大于0小于n,纵坐标均大于0。A国有一个不在(0,0)和(n,0)的首都。(0,0),(n,0)和首都这三个城市是一定需要保护的。
上图中,A,B,C,D,E点为A国城市,且目前都要保护,那么修建的防线就会是A-B-C-D,花费也就是线段AB的长度+线段BC的长度+线段CD的长度,如果,这个时候撤销B点的保护,那么防线变成下图
Input
第一行,三个整数n,x,y分别表示河边城市和首都是(0,0),(n,0),(x,y)。第二行,一个整数m。
接下来m行,每行两个整数a,b表示A国的一个非首都非河边城市的坐标为(a,b)。
再接下来一个整数q,表示修改和询问总数。
接下来q行每行要么形如1 i,要么形如2,分别表示撤销第i个城市的保护和询问。
Output
对于每个询问输出1行,一个实数v,表示修建防线的花费,保留两位小数Sample Input
4 2 12
1 2
3 2
5
2
1 1
2
1 2
2
Sample Output
6.475.84
4.47
HINT
m<=100000,q<=200000,n>1所有点的坐标范围均在10000以内, 数据保证没有重点
Source
[Submit][Status][Discuss]
HOME Back
学了一发动态维护凸包... 所以说算是一个增量法? 每次找到前后趋往两边删, 判断就用叉积判断就行了. 至于前后趋, 插入删除的用个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; }
相关文章推荐
- [BZOJ2300][HAOI2011]防线修建(平衡树动态维护凸包)
- bzoj 2300 [HAOI2011]防线修建 set动态维护凸包
- BZOJ 2300 [HAOI2011]防线修建 Splay维护动态凸包
- [平衡树动态维护凸包] BZOJ 2300 [HAOI2011]防线修建
- BZOJ 2300 HAOI 2011 防线修建 动态维护凸包
- bzoj 2300: [HAOI2011]防线修建(splay动态维护凸包)
- bzoj 2300 [HAOI2011]防线修建 splay维护凸包
- 【BZOJ2300】[HAOI2011]防线修建 set维护凸包
- BZOJ 2300 HAOI2011 防线修建 平衡树维护凸包
- [BZOJ2300][HAOI2011][动态凸包]防线修建
- BZOJ 2300: [HAOI2011]防线修建( 动态凸包 )
- bzoj2300: [HAOI2011]防线修建【动态凸包】
- 【bzoj2300】[HAOI2011]防线修建 离线+STL-set维护凸包
- 【BZOJ 2300】 [HAOI2011]防线修建 平衡树维护凸包
- bzoj2300 [HAOI2011]防线修建 离线凸包
- bzoj2300: [HAOI2011]防线修建 计算几何 凸包
- 【BZOJ 2300】 2300: [HAOI2011]防线修建 (动态凸包+set)
- BZOJ [HAOI2011]防线修建(动态凸包)
- BZOJ 2300: [HAOI2011]防线修建|set维护凸壳
- 2300: [HAOI2011]防线修建 set维护凸包