题目描述
近来A国和B国的矛盾激化,为了预防不测,A国准备修建一条长长的防线,当然修建防线的话,肯定要把需要保护的城市修在防线内部了。可是A国上层现在还犹豫不决,到底该把哪些城市作为保护对象呢?又由于A国的经费有限,所以希望你能帮忙完成如下的一个任务:
给出你所有的A国城市坐标
A国上层经过讨论,考虑到经济问题,决定取消对i城市的保护,也就是说i城市不需要在防线内了
A国上层询问对于剩下要保护的城市,修建防线的总经费最少是多少
你需要对每次询问作出回答。注意单位1长度的防线花费为1。
A国的地形是这样的,形如下图,x轴是一条河流,相当于一条天然防线,不需要你再修建
A国总是有两个城市在河边,一个点是(0,0),一个点是(n,0),其余所有点的横坐标均大于0小于n,纵坐标均大于0。A国有一个不在(0,0)和(n,0)的首都。(0,0),(n,0)和首都这三个城市是一定需要保护的。
输入输出格式
输入格式:
第一行,三个整数n,x,y分别表示河边城市和首都是(0,0),(n,0),(x,y)。
第二行,一个整数m。
接下来m行,每行两个整数a,b表示A国的一个非首都非河边城市的坐标为(a,b)。
再接下来一个整数q,表示修改和询问总数。
接下来q行每行要么形如1 i,要么形如2,分别表示撤销第i个城市的保护和询问。
输出格式:
对于每个询问输出1行,一个实数v,表示修建防线的花费,保留两位小数
输入输出样例
说明
数据范围:
30%的数据m<=1000,q<=1000
100%的数据m<=100000,q<=200000,n>1
所有点的坐标范围均在10000以内, 数据保证没有重点
本题是动态凸包裸题。我们考虑用set维护在凸包上的点,set以横坐标排序。每一次插入一个点的时候先查询是否在凸包内,查询的方法为在set中二分出该点左右的点,判断点是否在这两点连成的直线下。如果不在凸包内,我们就插入该点,每一次插入弹出左右两边不符合凸包性质的点,并且时刻更新周长即可。
#include<cstdio> #include<cmath> #include<set> using namespace std; const int maxn = 1e5 + 5, inf = 0x3f3f3f3f; typedef pair<int, int> pii; set<pii > up; set<pii >::iterator it, lst, ml, mr; int xMX, cx, cy, n, q, opr[maxn][2], vis[maxn]; double k, b, mx, my, C, mk; pii pos[maxn]; bool InCon(int x, int y) { it = up.lower_bound(make_pair(x, -inf)), mr = it; mx = (double) (it -> first), my = (double) (it -> second); k = ((double)(--it) -> second - my) / ((double)(it) -> first - mx); b = my - (k * mx), mk = k, ml = it; return (k * x + b) >= y; } #define sqr(a) ((double)(a) * (a)) inline double Gdis(pii a, pii b) { return sqrt(sqr(a.first - b.first) + sqr(a.second - b.second)); } void InsPos(int x, int y) { if(InCon(x, y)) return ; C -= Gdis(*ml, *mr), it = ml; while(1) { mx = it -> first, my = it -> second, lst = it--; if(lst == up.begin()) break; k = ((double)(it) -> second - my) / ((double)(it) -> first - mx); if(k <= ((double)y - (double)(lst) -> second) / ((double)x - (double)(lst) -> first)) C -= Gdis(*lst, *it), up.erase(lst); else break; } C += Gdis(*lst, make_pair(x, y)); it = mr, k = mk; while(1) { mx = it -> first, my = it -> second, lst = it++; if(it == up.end()) break; k = ((double)(it) -> second - my) / ((double)(it) -> first - mx); if(k >= ((double)(lst) -> second - (double)y) / ((double)(lst) -> first - (double)x)) C -= Gdis(*lst, *it), up.erase(lst); else break; } C += Gdis(*lst, make_pair(x, y)); up.insert(make_pair(x, y)); } void prt(int st) { double ans = 0; if(st == 0) return; if(opr[st][0] == 1) InsPos(pos[opr[st][1]].first, pos[opr[st][1]].second); ans = C, prt(st - 1); if(opr[st][0] == 2) printf("%.2lf\n", ans); } int main() { scanf("%d%d%d", &xMX, &cx, &cy); up.insert(make_pair(xMX, 0)); up.insert(make_pair(0, 0)); up.insert(make_pair(cx, cy)); C = Gdis(make_pair(xMX, 0), make_pair(cx, cy)); C += Gdis(make_pair(0, 0), make_pair(cx, cy)); scanf("%d", &n); for(register int i = 1; i <= n; ++i) scanf("%d%d", &pos[i].first, &pos[i].second); scanf("%d", &q); for(register int i = 1; i <= q; ++i) { scanf("%d", &opr[i][0]); if(opr[i][0] == 2) continue; scanf("%d", &opr[i][1]), vis[opr[i][1]] = 1; } for(register int i = 1; i <= n; ++i) if(!vis[i]) InsPos(pos[i].first, pos[i].second); prt(q); return 0; }
没有帐号? 立即注册