BZOJ 2300 防线修建
http://www.lydsy.com/JudgeOnline/problem.php?id=2300
题意:给点,有以下操作:删去一个点,询问这些点构成凸包的周长。
思路:用splay维护上凸壳,splay排序的关键字是X,同时还要记录每个点与左右点的斜率,当加入一个点时,我们找到它应该在的X的位置,一个个减掉左边,一个个减掉右边,符合条件就是当左边的斜率大于右边的斜率,就表明它在凸包上。
PS:如果当前加入点的左边斜率小于右边斜率,说明它在凸包内,可以直接删掉这个点。
#include<cstdio> #include<cmath> #include<cstring> #include<iostream> #include<algorithm> struct node{ int id,val,opt; }q[200005]; struct point{ double x,y; }p[200005]; const double eps=1e-9; int tmp,root; double c[200005],xx[200005],yy[200005],ans,rk[200005],lk[200005]; int n,ch[200005][2],fa[200005],vis[200005]; int read(){ int t=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();} return t*f; } void rotate(int x,int &rt){ int y=fa[x],z=fa[y],l,r; if (ch[y][0]==x) l=0;else l=1;r=l^1; if (y!=rt){ if (ch[z][0]==y) ch[z][0]=x;else ch[z][1]=x; }else rt=x; fa[x]=z;fa[y]=x;fa[ch[x][r]]=y; ch[y][l]=ch[x][r];ch[x][r]=y; } void splay(int x,int &rt){ while (x!=rt){ int y=fa[x],z=fa[y]; if (y!=rt){ if (ch[z][0]==y^ch[y][0]==x) rotate(x,rt); else rotate(y,rt); } rotate(x,rt); } } void find(int k,double X){ if (!k) return; if (xx[k]<X+eps) tmp=k,find(ch[k][1],X); else find(ch[k][0],X); } int suc(int x){ x=ch[x][1]; while (ch[x][0]) x=ch[x][0]; return x; } int pre(int x){ x=ch[x][0]; while (ch[x][1]) x=ch[x][1]; return x; } double sqr(double x){ return x*x; } double dis(int x,int y){ if (!x||!y) return 0.0; return sqrt(sqr(xx[x]-xx[y])+sqr(yy[x]-yy[y])); } void getslope(int x,int y){ if (!x){lk[y]=1e9;return;} if (!y){rk[x]=-1e9;return;} if (fabs(xx[x]-xx[y])<1e-9){ if (yy[x]<yy[y]) rk[x]=lk[y]=1e9; else rk[x]=lk[y]=-1e9; return; } rk[x]=lk[y]=(yy[x]-yy[y])/(xx[x]-xx[y]); } void insert(double X,double Y,int id){ tmp=0; find(root,X);int x=tmp,y=0; if (!x){ x=root; while (ch[x][0]) x=ch[x][0]; splay(x,root); y=x;x=0; }else splay(x,root),splay(y=suc(x),ch[x][1]); xx[id]=X;yy[id]=Y; if (y) fa[id]=y,ch[y][0]=id; else fa[id]=x,ch[x][1]=id; getslope(x,id);getslope(id,y); ans-=dis(x,y); if (rk[id]>=lk[id]){getslope(x,y);fa[id]=0;ch[y][0]=0;ans+=dis(x,y);return;} splay(id,root); root=id; x=pre(id); ans+=dis(x,id); while (lk[x]<=rk[x]&&x){ y=pre(x); splay(y,ch[x][0]); ans-=dis(x,id); ans-=dis(x,y); ans+=dis(y,id); fa[x]=ch[x][0]=ch[x][1]=0; ch[id][0]=y;fa[y]=id; getslope(y,id); x=y; } x=suc(id); ans+=dis(x,id); while (lk[x]<=rk[x]&&x){ y=suc(x); splay(y,ch[x][1]); ans-=dis(x,id); ans-=dis(x,y); ans+=dis(y,id); fa[x]=ch[x][1]=ch[x][0]=0; ch[id][1]=y;fa[y]=id; getslope(id,y); x=y; } } int main(){ int m=read(),x=read(),y=read(); n=read(); for (int i=1;i<=n;i++) scanf("%lf%lf",&p[i].x,&p[i].y); int T=read(); for (int i=1;i<=T;i++){ q[i].opt=read(); if (q[i].opt==2) continue; q[i].id=i;q[i].val=read();vis[q[i].val]=1; } insert(0,0,1); insert(m,0,2); insert(x,y,3); for (int i=1;i<=n;i++) if (!vis[i]){ insert(p[i].x,p[i].y,i+3); } int top=0; for (int i=T;i>=1;i--){ if (q[i].opt==2){ c[++top]=ans; }else{ insert(p[q[i].val].x,p[q[i].val].y,q[i].val+3); } } for (int i=top;i>=1;i--) printf("%.2f\n",c[i]); }