题解:P2521 [HAOI2011] 防线修建
Cryn_Frog195 · · 题解
题意
给出
解法
由于题目没有强制在线,先考虑离线。
我们发现凸包删点事件非常麻烦的事情,考虑将一直没删的点建立凸包后再倒序加点,这时如果存在同时增删点则做线段树分治。
加点时先考虑所加点是否在凸包外,在凸包里面的不加入。另外加入是注意两边都要判断,如果出现左拐则删除,保证凸包涉及的边按顺时针(从左到右)顺序斜率单减。注意比较时用浮点数不好,建议交叉相乘。
维护时考虑用 stl :: set,这样我们会有总体
代码
//c++14 O2,213ms,3.59mb,2.52kb
#include<bits/stdc++.h>
using namespace std;
int n,m,q,tp[200009],id[200009],x,y,a[100009],b[100009];
bool vis[200009];
set<pair<int,int> >p;
double ans,prt[200009];
double dis(int x1,int y1,int x2,int y2){
return __builtin_sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
}
void delnode(set<pair<int,int> > :: iterator x){
auto y = x,z = x;
//printf("d %d %d\n",x -> first,x -> second);
y ++,z --;
ans -= dis(y -> first,y -> second,x -> first,x -> second);
ans -= dis(z -> first,z -> second,x -> first,x -> second);
ans += dis(y -> first,y -> second,z -> first,z -> second);
p.erase(x);
// printf("%.2lf\n",ans);
}
void addnode(int x,int y){
//printf("a %d %d\n",x,y);
auto fx = p.insert(make_pair(x,y)).first;
auto fy = fx,z = fx;
fy ++,z --;
//printf("%d %d %d %d\n",fy -> first,fy -> second,z -> first,z -> second);
ans += dis(fy -> first,fy -> second,fx -> first,fx -> second);
ans += dis(z -> first,z -> second,fx -> first,fx -> second);
ans -= dis(fy -> first,fy -> second,z -> first,z -> second);
}
void pop(int x,int y){
auto o = p.lower_bound(make_pair(x,y)),fp = o;
if(o == p.end())
return;
fp ++;
while(p.end() != fp && (o -> second - y) * (fp -> first - o -> first) <= (o -> first - x) * (fp -> second - o -> second))
delnode(o),o = fp,fp ++;
o --;
fp = o;
if(o == p.begin())
return;
fp --;
while((y - o -> second) * (o -> first - fp -> first) >= (x - o -> first) * (o -> second - fp -> second)){
delnode(o);
o = fp;
if(o != p.begin())
fp --;
else
break;
}
}
void ins(int x,int y){
auto o = p.lower_bound(make_pair(x,y));
auto fp = o;
fp --;
if(o -> first == x)
return;
else if(fp -> first == x){
delnode(fp);
pop(x,y);
addnode(x,y);
}
else if((o -> second - y) * (x - fp -> first) < (o -> first - x) * (y - fp -> second))
pop(x,y),addnode(x,y);
}
/*
Author:OtterZ
Tag:offline,slope trick,geometry
*/
int main(){
scanf("%d %d %d",&n,&x,&y);
ans = __builtin_sqrt(x * x + y * y) + __builtin_sqrt((n - x) * (n - x) + y * y);
p.insert(make_pair(0,0)),p.insert(make_pair(n,0)),p.insert(make_pair(x,y));
scanf("%d",&m);
for(int i = 1; i <= m; i ++){
scanf("%d %d",&a[i],&b[i]);
}
scanf("%d",&q);
for(int i = 1; i <= q; i ++){
scanf("%d",&tp[i]);
if(tp[i] == 1){
scanf("%d",&id[i]);
if(vis[id[i]])
id[i] = 0;
vis[id[i]] = true;
}
}
for(int i = 1; i <= m; i ++)
if(!vis[i])
ins(a[i],b[i]);
for(int i = q; i > 0; i --){
if(id[i] != 0)
ins(a[id[i]],b[id[i]]);
else if(tp[i] == 2)
prt[i] = ans;
//printf("%.2lf\n",ans);
}
for(int i = 1; i <= q; i ++)
if(tp[i] == 2)
printf("%.2lf\n",prt[i]);
return 0;
}