bzoj2300【HAOI2011】防线修建 (动态凸包 平衡树 set)

凸包上删点我不会,那就将删点转成加点。
所以我们只要维护一个可以加点的动态凸包就好了。

每次加点先判断是否在凸包内,然后用set lowerbound找两边相邻的点,对两边分别进行维护。

#include <bits/stdc++.h>
#define pb push_back
#define memarray(array,val) memset(array,val,sizeof(array))
using namespace std;
const int mod=1e9+7;
const double PI=acos(-1.0);
const double EPS=1e-6;
inline int sgn(double a){
    if(a<-EPS)return -1;
    return a>EPS;
}
inline int cmp(double a,double b){
    return sgn(a-b);
}
const int MAXN=2e5+10;
const int INF=0x3f3f3f3f;
int n,m,q;
int ty[MAXN],cancel[MAXN];
bool no[MAXN];
double ans;
struct Point{
    double x,y;
    Point(double _x=0.0,double _y=0.0){
        x=_x;y=_y;
    }
    double len(){
        return sqrt(len2());
    }
    double len2(){
        return x*x+y*y;
    }
    void read(){
        scanf("%lf%lf",&x,&y);
    }
    bool operator<(const Point p)const{
        if(cmp(x,p.x)==0)return y<p.y;
        return x<p.x;
    }
    Point operator+(const Point p)const{
        return (Point){x+p.x,y+p.y};
    }
    Point operator-(const Point p)const{
        return (Point){x-p.x,y-p.y};
    }
    double operator*(const Point p)const{
        return x*p.x+y*p.y;
    }
    double operator^(const Point p)const{
        return x*p.y-y*p.x;
    }
}p[MAXN],ptmp[MAXN];
Point p1,p2,p3;
set<Point>stk;
int Andrew(){
    int num=0;
    for(int i=1;i<=n;i++){
        if(no[i])continue;
        ptmp[++num]=p[i];
    }
    ptmp[++num]=p1;
    ptmp[++num]=p2;
    ptmp[++num]=p3;
    sort(ptmp+1,ptmp+1+num);
    stk.insert(ptmp[num]);
    int len=1;
    for(int i=num-1;i>=1;i--){
        while(len>1){
            set<Point>::iterator sss=stk.begin();
            Point t1=*sss;
            sss++;
            Point t2=*sss;
            if(sgn(((t1-t2)^(ptmp[i]-t2)))<0){
                stk.erase(stk.begin());
                len--;
            }else{
                break;
            }
        }
        stk.insert(ptmp[i]);
        len++;
    }
    return len;
}
void insert(int idx){
    Point point=p[idx];
    set<Point>::iterator it,it2;
    it=lower_bound(stk.begin(),stk.end(),point);
    it2=it;
    it2--;
    Point point1=*it2,point2=*it;
    if(sgn(((point1-point2)^(point-point2)))>=0)return;
    ans-=(point1-point2).len();
    while(it2!=stk.begin()){
        it2--;
        point2=*it2;
        if(sgn(((point2-point)^(point1-point)))>0){
            stk.erase(point1);
            ans-=(point1-point2).len();
            point1=point2;
        }else{
            break;
        }
    }
    Point leftPoint=point1;
    it2=it;
    point1=*it2;
    it2++;
    while(it2!=stk.end()){
        point2=*it2;
        if(sgn(((point1-point)^(point2-point)))>0){
            stk.erase(point1);
            ans-=(point1-point2).len();
            point1=point2;
            it2++;
        }else{
            break;
        }
    }
    if(sgn(((point-point1)^(leftPoint-point1)))>=0){
        stk.insert(point);
        ans+=(point-leftPoint).len();
        ans+=(point-point1).len();
    }
}
void solve() {
    Andrew();
    Point pre={0,0};
    for(auto i:stk){
        ans+=(i-pre).len();
        pre=i;
    }
    stack<double>two;
    for(int i=q;i>=1;i--){
        if(ty[i]==2){
            two.push(ans);
        }else{
            insert(cancel[i]);
        }
    }
    while(!two.empty()){
        double tmp=two.top();
        two.pop();
        printf("%.2f\n",tmp);
    }
}
void init(){
    double x,y;
    scanf("%lf",&x);
    p1=(Point){0,0};
    p2=(Point){x,0};
    scanf("%lf%lf",&x,&y);
    p3=(Point){x,y};
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        p[i].read();
    scanf("%d",&q);
    for(int i=1;i<=q;i++){
        scanf("%d",ty+i);
        if(ty[i]==1){
            scanf("%d",cancel+i);
            no[cancel[i]]=true;
        }
    }
}
int main()
{
    int T=1;
//    scanf("%d",&T);
    while(T--)
    {
        init();
        solve();
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值