BZOJ2300: [HAOI2011]防线修建

7 篇文章 0 订阅
6 篇文章 0 订阅

每次删一个点或询问剩余点的凸包周长


删一个点好麻烦呀,考虑离线,倒着操作将删点改为加点
然后就简单了,用一颗平衡树维护凸包中的点,倒着把点加回去
splay可以用set
论熟练运用STL


code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define inf 1e9
using namespace std;

const int maxn = 110000;
struct node
{
    int x,y;
    node(){}
    node(int _x,int _y){x=_x;y=_y;}
}a[maxn],up,zero; int n;
int mul(node x,node y)
{
    return x.x*y.y-x.y*y.x;
}
int multi(node x,node y,node z)
{
    x.x-=z.x; x.y-=z.y;
    y.x-=z.x; y.y-=z.y;
    return x.x*y.y-x.y*y.x;
}
bool judge(node x,node y){ return x.x==y.x&&x.y==y.y; }
bool operator <(node x,node y)
{
    return mul(x,y)>0||(mul(x,y)==0&&x.x<y.x);
}
double dis(node x,node y)
{
    double x1=x.x-y.x,y1=x.y-y.y;
    return sqrt((x1*x1)+(y1*y1));
}

stack<double> T;
bool vis[maxn];
int q[maxn];
int m;
double ret;
set<node>S;
set<node>::iterator it;

void ins(node x)
{
    it=S.lower_bound(x);
    set<node>::iterator l,r,ll,rr;
    r=it;
    it--; l=it;
    if(mul(*r,x)==0) return ;
    if(judge(*r,up))
    {
        ll=l; ll--;
        if(multi(*l,*ll,x)<0)
        {
            S.insert(x);
            ret+=dis(zero,x)+dis(x,*l)-dis(zero,*l);
            return ;
        }
        ret-=dis(zero,*l);
        for(;!judge(*ll,zero);l=ll,ll--)
        {
            if(multi(*l,*ll,x)<0) break;
            ret-=dis(*l,*ll);
            S.erase(*l);
        }
        S.insert(x);
        ret+=dis(x,zero)+dis(x,*l);
        return ;
    }
    if(multi(x,*r,*l)<=0) return ;
    ret-=dis(*l,*r);
    for(rr=r,rr++;!judge(*rr,up);r=rr,rr++)
    {
        if(multi(*r,*rr,x)>0) break;
        ret-=dis(*r,*rr);
        S.erase(*r);
    }
    ret+=dis(x,*r);
    for(ll=l,ll--;!judge(*ll,zero);l=ll,ll--)
    {
        if(multi(*l,x,*ll)>0) break;
        ret-=dis(*l,*ll);
        S.erase(*l);
    }
    ret+=dis(x,*l);
    S.insert(x);
}

int main()
{
    int x,y,c; scanf("%d%d%d",&c,&x,&y);
    node zero=node(0,0); S.insert(zero);
    node a2=node(c,0); S.insert(a2);
    node a3=node(x,y); S.insert(a3);
    up=node(0,1);
    S.insert(up);
    ret=dis(a2,a3)+dis(zero,a3);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&x,&y);
        a[i]=node(x,y);
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&x);
        if(x==2) q[i]=0;
        else scanf("%d",&q[i]),vis[q[i]]=true;
    }
    for(int i=1;i<=n;i++) if(!vis[i]) ins(a[i]);
    for(int i=m;i>=1;i--)
    {
        if(!q[i]) T.push(ret);
        else ins(a[q[i]]);
    }
    while(!T.empty()) printf("%.2lf\n",T.top()),T.pop();

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值