记录编号 55188 评测结果 AAAAAAAAAA
题目名称 [HAOI 2011]防线修建 最终得分 100
用户昵称 Gravatarcstdio 是否通过 通过
代码语言 C++ 运行时间 0.856 s
提交时间 2013-03-16 14:37:49 内存使用 1.94 MiB
显示代码纯文本
#include<iostream>
#include<cstdio>
#include<set>
#include<deque>
#include<cmath>
#include<iomanip>
using namespace std;
class POINT{
public:
	int x,y;
	double s;//相邻两边长度
};
bool operator <(POINT a,POINT b){
	if(a.x<b.x) return 1;
	if(a.x>b.x) return 0;
	if(a.y<b.y) return 1;
	return 0;
}
bool operator ==(POINT a,POINT b){
	return a.x==b.x;
}
bool under(POINT a,POINT b,POINT s){//点s是否在线段ab下方
	if(s.x==a.x) return s.y<a.y;
	if(s.x==b.x) return s.y<b.y;
	//两个向量:s到a和s到b
	int x1=a.x-s.x,y1=a.y-s.y;
	int x2=b.x-s.x,y2=b.y-s.y;
	int temp=x1*y2-x2*y1;
	return temp<0;//<0意味着在下方
}
bool under1(POINT a,POINT b,POINT s){//点s是否在线段ab下方
	//这是用斜率写的奇葩函数......具体到这道题上是正确的
	if(s.x==a.x) return s.y<a.y;
	if(s.x==b.x) return s.y<b.y;
	double k1=(double)(s.y-a.y)/(double)(s.x-a.x);
	double k2=(double)(b.y-a.y)/(double)(b.x-a.x);
	return k1<k2;
}
double dis(POINT a,POINT b){
	double ans;
	ans=(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
	return sqrt(ans);
}
set<POINT> hull;//凸包
deque<POINT> city;//每个城市
int m,q;//m个城市,q个修改和询问
int mark[200001]={0},data[200001]={0};//mark是标识符,data是城市编号
bool uninc[100010]={0};
deque<double> ans;
double sum;
void out(void){
	set<POINT> ::iterator km;
	km=hull.begin();
	while(km!=hull.end()){
		cout<<(*km).x<<" "<<(*km).y<<endl;
		km++;
	}
	cout<<endl;
}
void add(POINT s){//把点s加入凸包
	hull.insert(s);
	set<POINT> ::iterator now,left,right,last;
	now=hull.find(s);
	left=right=now;
	left--,right++;
	if(under(*left,*right,*now)){//已在包内
		hull.erase(now);
		return;
	}
	sum-=dis(*left,*right);
	sum+=dis(*left,*now)+dis(*now,*right);
	last=left;
	if(last==hull.begin()) goto NEXT;
	left--;
	while(under(*left,*now,*last)){//把last这个点删掉
		if(last==hull.begin()) break;
		sum-=dis(*now,*last)+dis(*last,*left);
		sum+=dis(*now,*left);
		hull.erase(last);
		if(left==hull.begin()) break;
		last=left;
		left--;
	}
	NEXT:;
	last=right;
	right++;
	if(right==hull.end()) goto END;
	while(under(*now,*right,*last)){//把last这个点删掉
		if(right==hull.end()){
			break;
		}
		sum-=dis(*now,*last)+dis(*last,*right);
		sum+=dis(*now,*right);
		hull.erase(last);
		last=right;
		right++;//这一句开始写成left了,然后调了两天!!!!!!!!!!!!!!!!!!!!
		if(right==hull.end()){
			break;
		}
	}
	END:;
}
 
void read(void){
	int n,x,y;
	scanf("%d%d%d",&n,&x,&y);
	//三个点(0,0),(n,0),(x,y)
	POINT temp;
	temp.x=temp.y=0;
	city.push_back(temp);
	temp.x=n,temp.y=0;
	city.push_back(temp);
	temp.x=x,temp.y=y;
	city.push_back(temp);
	scanf("%d",&m);
	int i;
	for(i=0;i<m;i++){
		scanf("%d%d",&temp.x,&temp.y);
		city.push_back(temp);
	}
	m+=3;
	city[0].s=dis(city[0],city[2]);
	city[1].s=dis(city[1],city[2]);
	sum=city[2].s=city[0].s+city[1].s;
	hull.insert(city[0]);
	hull.insert(city[1]);
	hull.insert(city[2]);//最初的三个城市加进去
	//0和1是两个河边,2是首都
	scanf("%d",&q);
	for(i=0;i<q;i++){
		scanf("%d",&mark[i]);
		if(mark[i]==1){
			scanf("%d",&data[i]);
			data[i]+=2;
			uninc[data[i]]=true;
		}
	}
	for(i=3;i<m;i++){
		if(!uninc[i]) add(city[i]);
	}
}
double count(void){
	set<POINT> ::iterator km,last;
	last=km=hull.begin();
	km++;
	double ans=0;
	while(km!=hull.end()){
		ans+=dis(*last,*km);
		last=km;
		km++;
	}
	return ans;
}
void work(void){
	int i;
	for(i=q-1;i>=0;i--){
		if(mark[i]==2) ans.push_front(sum);
		else add(city[data[i]]);
		set<POINT> ::iterator km;
		km=hull.begin();
	}
}
void write(void){
	int i;
	for(i=0;i<ans.size();i++) cout<<ans[i]<<endl;
}
int main(){
	freopen("defense.in","r",stdin);
	freopen("defense.out","w",stdout);
	cout<<setiosflags(ios::fixed)<<setprecision(2);
	read();
	work();
	write();
	return 0;
}