Bzoj2300 / 洛谷P2521 [HAOI2011]防线修建

题目描述

近来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)和首都这三个城市是一定需要保护的。

输入输出格式

输入格式:

 

第一行,三个整数n,x,y分别表示河边城市和首都是(0,0),(n,0),(x,y)。

第二行,一个整数m。

接下来m行,每行两个整数a,b表示A国的一个非首都非河边城市的坐标为(a,b)。

再接下来一个整数q,表示修改和询问总数。

接下来q行每行要么形如1 i,要么形如2,分别表示撤销第i个城市的保护和询问。

 

输出格式:

 

对于每个询问输出1行,一个实数v,表示修建防线的花费,保留两位小数

 

输入输出样例

输入样例#1:
4 2 1                                
2                                 
1 2                               
3 2                               
5                                 
2
1 1
2
1 2
2
输出样例#1:
6.47
5.84
4.47

说明

数据范围:

30%的数据m<=1000,q<=1000

100%的数据m<=100000,q<=200000,n>1

所有点的坐标范围均在10000以内, 数据保证没有重点

 

数学问题 计算几何 凸包

由于下边不用考虑,实际上我们只需要维护一个上凸壳。

离线询问,倒序加点,如果新加入的点在凸壳下面,就无视它,如果在凸壳上面,就将它加入凸壳,并删除原凸壳上的无用点。

凸壳上的点集可以用set或者平衡树维护。

 

倒序加点的时候忘了把没被删过的点先加进去,WA了一发

 

  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<cmath>
  6 #include<vector>
  7 #include<set>
  8 using namespace std;
  9 const double eps=1e-7;
 10 const int mxn=200010;
 11 int read(){
 12     int x=0,f=1;char ch=getchar();
 13     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 14     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
 15     return x*f;
 16 }
 17 struct point{
 18     double x,y;
 19     point operator + (point b){return (point){x+b.x,y+b.y};}
 20     point operator - (point b){return (point){x-b.x,y-b.y};}
 21     double operator * (point b){return x*b.x+y*b.y;}
 22     bool operator < (point b)const{
 23         return x<b.x || (x==b.x && y<b.y);
 24     }
 25 }a[mxn];
 26 int cnt=0;
 27 double Cross(point a,point b){
 28     return a.x*b.y-a.y*b.x;
 29 }
 30 double dist(point a,point b){
 31     return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
 32 }
 33 struct query{
 34     int id,tp;
 35 }q[mxn];
 36 struct cmp{bool operator () (const int c,const int d){return a[c].x<a[d].x;}};
 37 set<int,cmp>st;
 38 double nowans,ans[mxn];
 39 int top=0;
 40 void solve(int x){
 41     set<int,cmp>::iterator it,iL,iR;
 42     it=st.lower_bound(x);
 43     iL=it;iL--;
 44     int L=*iL,R=*it;
 45     if(Cross(a[x]-a[L],a[R]-a[x])>0)return;//在已有凸壳内
 46     nowans-=dist(a[L],a[R]);
 47     while(1){
 48         R=*it;it++;
 49         if(it==st.end())break;
 50         if(Cross(a[R]-a[x],a[*it]-a[x])>0){
 51             nowans-=dist(a[R],a[*it]);
 52             st.erase(R);
 53         }
 54         else break;
 55     }
 56     while(1){
 57         if(iL==st.begin())break;
 58         L=*iL;iL--;
 59         if(Cross(a[L]-a[*iL],a[x]-a[*iL])>0){
 60             nowans-=dist(a[*iL],a[L]);
 61             st.erase(L);
 62         }
 63         else break;
 64     }
 65     st.insert(x);
 66     it=st.find(x);
 67     iL=it;iL--;iR=it;iR++;
 68     nowans+=dist(a[*iL],a[x])+dist(a[x],a[*iR]);
 69     return;
 70 }
 71 bool vis[mxn];
 72 int n,m,Q;
 73 int main(){
 74 //    freopen("defense.in","r",stdin);
 75 //    freopen("defense.out","w",stdout);
 76     int i,j,x,y;
 77     n=read();x=read();y=read();
 78     a[++cnt]=(point){0,0};a[++cnt]=(point){n,0};a[++cnt]=(point){x,y};
 79     st.insert(1);st.insert(2);st.insert(3);
 80     nowans+=dist(a[2],a[3])+dist(a[1],a[3]);
 81     m=read();
 82     for(i=1;i<=m;i++){
 83         ++cnt;
 84         a[cnt].x=read();a[cnt].y=read();
 85     }
 86     Q=read();
 87     for(i=1;i<=Q;i++){
 88         q[i].tp=read();
 89         if(q[i].tp==1) q[i].id=read(),vis[q[i].id]=1;
 90     }
 91     for(i=1;i<=m;i++){
 92         if(!vis[i])solve(i+3);
 93     }
 94     for(i=Q;i;i--){
 95         if(q[i].tp==2){
 96             ans[++top]=nowans;
 97             continue;
 98         }
 99         solve(q[i].id+3);
100     }
101     while(top){
102         printf("%.2f\n",ans[top--]);
103     }
104     return 0;
105 }

 

posted @ 2017-04-05 15:23  SilverNebula  阅读(210)  评论(0编辑  收藏  举报
AmazingCounters.com