[HAOI2011]防线修建
题目描述
近来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以内, 数据保证没有重点
离线后问题变成维护动态凸壳,只有插入点的操作,根据x坐标维护平衡二叉树,
插入点x,找到x点的左右两点,判断x是否在凸壳外,然后维护x两边的凸壳
因为set是红黑树实现,把凸包的点放进set.
iterator x=s.begin();
x--;
x++;
此时x不一定等于s.begin()
#include<iostream> #include<set> #include<math.h> #include<stdio.h> #include<stdlib.h> using namespace std; typedef struct{ double x,y; bool shouldInsert; }Point; Point p[100005]; set<Point> s; double now=0; bool operator<(const Point& a,const Point&b){ return a.x<b.x||(a.x==b.x&&a.y<b.y); } Point operator-(const Point&a,const Point&b){ Point c; c.x=a.x-b.x; c.y=a.y-b.y; return c; } double dist(const Point&a,const Point&b){ Point c=a-b; return sqrt(c.x*c.x+c.y*c.y); } double cross(const Point&a,const Point&b){ return a.x*b.y-a.y*b.x; } void insert(int d){ set<Point>::iterator left=s.upper_bound(p[d]),right=left--,tmpr,tmpl; if(cross(*left-p[d],*right-p[d])<=0) return; now-=dist(*left,*right); while(true) { tmpr=right;right++; if(right==s.end()) break; if(cross(p[d]-*right,*tmpr-*right)>=0) { now-=dist(*tmpr,*right); s.erase(tmpr); } else break; } while(true) { tmpl=left;left--; if(tmpl==s.begin()) break; if(cross(p[d]-*left,*tmpl-*left)<=0) { now-=dist(*tmpl,*left); s.erase(tmpl); } else break; } s.insert(p[d]); now+=dist(p[d],*tmpl)+dist(p[d],*tmpr); } double ans[200005]; int main() { int n; double x,y; scanf("%d",&n); scanf("%lf %lf",&x,&y); Point a,b,c; a.x=0;a.y=0;b.x=n;b.y=0;c.x=x;c.y=y; s.insert(a);s.insert(b);s.insert(c); now+=dist(a,c)+dist(b,c); int m; scanf("%d",&m); for(int i=1;i<=m;++i) { scanf("%lf %lf",&x,&y); p[i].x=x;p[i].y=y;p[i].shouldInsert=true; } int q; int delCount=0;int delCity[200005]; int queryCount=0;int queryCity[200005]; scanf("%d",&q); for(int i=1;i<=q;++i) { int cmd,city; scanf("%d",&cmd); if(cmd==1) { scanf("%d",&city); delCount++; delCity[delCount]=city; p[city].shouldInsert=false; } if(cmd==2) {queryCount++;queryCity[queryCount]=delCount;} } for(int i=1;i<=m;++i) if(p[i].shouldInsert==true) insert(i); for(int i=queryCount;i>=1;--i) { while(delCount>queryCity[i]) { insert(delCity[delCount]); delCount--; } ans[i]=now; } for(int i=1;i<=queryCount;++i) printf("%.2f\n",ans[i]); }