BZOJ 2300 防线修建(set维护凸包)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2300

题意:给出一些点,两种操作:(1)删掉某个点;(2)求剩下点构成的凸包的周长。(保证凸包有一条边为x轴,即保证凸包上有两点在x轴上,这条边不算在周长中)

思路:离线。先将所有删掉的点删掉,其余点找到一个中心点(由题意其余点至少三个所以中心点存在),求每个点关于中心角的转角,以转角为关键字建立set。对于询问倒着操作,每次插入时找到两边的点将之间的删掉。如下图所示。

 

 



#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <map>




#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define abs(x) ((x)>=0?(x):-(x))
#define i64 long long
#define u32 unsigned int
#define u64 unsigned long long
#define clr(x,y) memset(x,y,sizeof(x))
#define CLR(x) x.clear()
#define ph(x) push(x)
#define pb(x) push_back(x)
#define Len(x) x.length()
#define SZ(x) x.size()
#define PI acos(-1.0)
#define sqr(x) ((x)*(x))
#define MP(x,y) make_pair(x,y)
#define EPS 1e-10




#define FOR0(i,x) for(i=0;i<x;i++)
#define FOR1(i,x) for(i=1;i<=x;i++)
#define FOR(i,a,b) for(i=a;i<=b;i++)
#define FORL0(i,a) for(i=a;i>=0;i--)
#define FORL1(i,a) for(i=a;i>=1;i--)
#define FORL(i,a,b)for(i=a;i>=b;i--)




#define rush() int CC;for(scanf("%d",&CC);CC--;)
#define Rush(n)  while(scanf("%d",&n)!=-1)
using namespace std;




void RD(int &x){scanf("%d",&x);}
void RD(i64 &x){scanf("%lld",&x);}
void RD(u64 &x){scanf("%I64u",&x);}
void RD(u32 &x){scanf("%u",&x);}
void RD(double &x){scanf("%lf",&x);}
void RD(int &x,int &y){scanf("%d%d",&x,&y);}
void RD(i64 &x,i64 &y){scanf("%lld%lld",&x,&y);}
void RD(u32 &x,u32 &y){scanf("%u%u",&x,&y);}
void RD(double &x,double &y){scanf("%lf%lf",&x,&y);}
void RD(int &x,int &y,int &z){scanf("%d%d%d",&x,&y,&z);}
void RD(i64 &x,i64 &y,i64 &z){scanf("%lld%lld%lld",&x,&y,&z);}
void RD(u32 &x,u32 &y,u32 &z){scanf("%u%u%u",&x,&y,&z);}
void RD(double &x,double &y,double &z){scanf("%lf%lf%lf",&x,&y,&z);}
void RD(char &x){x=getchar();}
void RD(char *s){scanf("%s",s);}
void RD(string &s){cin>>s;}




void PR(int x) {printf("%d\n",x);}
void PR(int x,int y) {printf("%d %d\n",x,y);}
void PR(i64 x) {printf("%lld\n",x);}
void PR(u32 x) {printf("%u\n",x);}
void PR(u64 x) {printf("%llu\n",x);}
void PR(double x) {printf("%.2lf\n",x);}
void PR(char x) {printf("%c\n",x);}
void PR(char *x) {printf("%s\n",x);}
void PR(string x) {cout<<x<<endl;}


void upMin(int &x,int y) {if(x>y) x=y;}
void upMin(i64 &x,i64 y) {if(x>y) x=y;}
void upMin(double &x,double y) {if(x>y) x=y;}
void upMax(int &x,int y) {if(x<y) x=y;}
void upMax(i64 &x,i64 y) {if(x<y) x=y;}
void upMax(double &x,double y) {if(x<y) x=y;}


const int mod=1000000000;
const i64 inf=((i64)1)<<60;
const double dinf=1000000000000000000.0;
const int INF=1000000005;
const int N=200005;


int DB(double x)
{
    if(x>1e-10) return 1;
    if(x<-1e-10) return -1;
    return 0;
}


struct node
{
    int x,y;
    double ang;
    
    node(){}
    node(int _x,int _y)
    {
        x=_x;
        y=_y;
    }
    
    
    int operator<(const node &a) const
    {
        return DB(ang-a.ang)<0;
    }
    
    int operator==(const node &a) const
    {
        return x==a.x&&y==a.y;
    }
    
    node operator-(node a)
    {
        return node(x-a.x,y-a.y);
    }


    int operator*(node a)
    {
        return x*a.y-y*a.x;
    }
};


int under(node a,node b,node s)
{
    a.x-=s.x; a.y-=s.y;
    b.x-=s.x; b.y-=s.y;
    return b.x*a.y-b.y*a.x<0;
}


double dis(node a,node b)
{
    a.x-=b.x;
    a.y-=b.y;
    return sqrt(1.0*a.x*a.x+1.0*a.y*a.y);
}


set<node> p;
double s;


#define type set<node>::iterator


type last(type it)
{
    if(it==p.begin()) it=p.end();
    return --it;
}


type next(type it)
{
    if(++it==p.end()) it=p.begin();
    return it;
}


int cross(node a,node b,node p)
{
    return (b-a)*(p-a);
}


double X,Y;


double getAng(node a)
{
    return atan2(a.y-Y,a.x-X);
}


void add(node a)
{
    type it=last(p.lower_bound(a));
    node b=*it,x,y;
    if(cross(b,*next(it),a)>0) return;
    type L=it,R=it;
    while(cross(a,*next(R),*R)>=0) R=next(R);
    while(cross(a,*L,*last(L))>=0) L=last(L);
    for(it=L;it!=R;it=next(it))
    {
        x=*it;
        y=*next(it);
        s-=dis(x,y);
    }
    for(it=next(L);it!=R;)
    {
        it=next(it);
        p.erase(last(it));
    }
    x=*L;y=*R;
    s+=dis(x,a)+dis(a,y);
    p.insert(a);
}


vector<node> V;


int q[N];
int n,x,y,m;


int op[N],a[N],Q;


int main()
{
    RD(n,x,y);
    V.pb(node(0,0));
    V.pb(node(n,0));
    V.pb(node(x,y));
    X=(n+x)/3.0;
    Y=y/3.0;
    V[0].ang=getAng(V[0]);
    V[1].ang=getAng(V[1]);
    V[2].ang=getAng(V[2]);
    RD(m);
    int i,k=3;
    FOR1(i,m) RD(x,y),V.pb(node(x,y)),V[k].ang=getAng(V[k]),k++;
    p.insert(V[0]);
    p.insert(V[1]);
    p.insert(V[2]);
    s=dis(V[0],V[2])+dis(V[1],V[2]);
    RD(Q);
    FOR1(i,Q)
    {
        RD(op[i]);
        if(op[i]==1) RD(a[i]),q[a[i]+2]=1;
    }
    m+=3;
    for(i=3;i<m;i++) if(!q[i]) add(V[i]);
    vector<double> A;
    for(i=Q;i>=1;i--)
    {
        if(op[i]==1) add(V[a[i]+2]);
        else A.pb(s);
    }
    for(i=SZ(A)-1;i>=0;i--) PR(A[i]);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值