【题目】
点击传送
【题解1】
题意就是给你一大堆点,要你求出凸包,然后每次可以删除一个点,问你删除之后的周长是多少。
对于30%,可以每删除一个点,就重新求凸包,复杂度O(N^2lbN)。
对于100%,考虑当你删掉一个点时,那么这个点原来连接的左右两点一定还在凸包上,而凸包有变化的区域只限于这两点之间(以极角序为参考),所以你就可以在这个区间里进行局部的凸包重建。这个做法的复杂度很玄学,当数据极端的时候会被卡掉的,但是出题人显然没考虑到这一点,轻松AC了。
【题解2】
听说这道题正解是,先读入所有操作,倒着看,就成了你要往凸包上插入一些点。然后用平衡树维护凸包,每次插入一个点,找到它按极角序应该在的位置,然后判断其左右会不会被覆盖(用叉积),用类似Graham的思想来做就好了。这样复杂度是O(NlbN)。网上大部分人都是用的set。
【代码(第一种算法)】
//凸包
#include <cstdio>
#include <cmath>
#include <algorithm>
#define maxn 100010
using namespace std;
struct vec{double x,y;int num;}p[maxn];
double C;
int N, top, left[maxn], right[maxn], s[maxn], table[maxn], on[maxn];
double cp(vec v1, vec v2){return v1.x*v2.y-v2.x*v1.y;}
bool cmp(vec p1, vec p2)
{
double c=cp(p1,p2);
return c==0?p1.x<p2.x or p1.y<p2.y:c>0;
}
void graham()
{
int i;
vec v1, v2;
s[++top]=1;
on[1]=true;
sort(p+2,p+N+1,cmp);
for(i=2;i<=N;i++)
{
v1=(vec){p[s[top]].x-p[s[top-1]].x,p[s[top]].y-p[s[top-1]].y,0};
v2=(vec){p[i].x-p[s[top]].x,p[i].y-p[s[top]].y,0};
while(top>1 and cp(v1,v2)<0)
{
on[s[top--]]=false;
v1=(vec){p[s[top]].x-p[s[top-1]].x,p[s[top]].y-p[s[top-1]].y,0};
v2=(vec){p[i].x-p[s[top]].x,p[i].y-p[s[top]].y,0};
}
right[i]=s[top];
left[s[top]]=i;
s[++top]=i;
on[i]=true;
}
for(i=N-1;p[i].x*p[s[top]].y-p[i].y*p[s[top]].x==0;i--)
right[i]=s[top],left[s[top]]=i,s[++top]=i;
right[s[1]]=s[top];
left[s[top]]=s[1];
}
double dist(vec p1, vec p2)
{
double t1=p1.x-p2.x, t2=p1.y-p2.y;
return sqrt(t1*t1+t2*t2);
}
void del(int num)
{
int l=left[num], r=right[num], i, x;
vec v1, v2;
p[num].num=-1;
if(!on[num])return;
else on[num]=false;
C-=dist(p[num],p[l])+dist(p[num],p[r]);
s[top=1]=r;
x=l==N?1:l+1;
for(i=r+1;i!=x;i=i==N?1:i+1)
{
if(p[i].num==-1)continue;
v1=(vec){p[s[top]].x-p[s[top-1]].x,p[s[top]].y-p[s[top-1]].y,0};
v2=(vec){p[i].x-p[s[top]].x,p[i].y-p[s[top]].y,0};
while(top>1 and cp(v1,v2)<0)
{
on[s[top--]]=false;
v1=(vec){p[s[top]].x-p[s[top-1]].x,p[s[top]].y-p[s[top-1]].y,0};
v2=(vec){p[i].x-p[s[top]].x,p[i].y-p[s[top]].y,0};
}
right[i]=s[top];
left[s[top]]=i;
s[++top]=i;
on[i]=true;
}
for(i=2;i<=top;i++)C+=dist(p[s[i]],p[s[i-1]]);
}
int main()
{
int x, y, q, i, a;
scanf("%d%d%d",&a,&x,&y);
p[1].x=p[1].y=0;
p[2].x=a,p[2].y=0;
p[3].x=x,p[3].y=y;
scanf("%d",&N),N+=3;
for(i=4;i<=N;i++)scanf("%lf%lf",&p[i].x,&p[i].y),p[i].num=i-3;
graham();
for(i=1;i<=N;i++)table[p[i].num]=i;
for(C=dist(p[s[1]],p[s[top]]),i=2;i<=top;i++)C+=dist(p[s[i]],p[s[i-1]]);
C-=a;
scanf("%d",&q);
for(i=1;i<=q;i++)
{
scanf("%d",&x);
if(x==1)scanf("%d",&y),del(table[y]);
else printf("%.2lf\n",C);
}
return 0;
}