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]);
}

 

posted @ 2016-07-14 17:12  GFY  阅读(157)  评论(0编辑  收藏  举报