zoukankan      html  css  js  c++  java
  • [bzoj2300] [HAOI2011]防线修建

    Description

    近来A国和B国的矛盾激化,为了预防不测,A国准备修建一条长长的防线,当然修建防线的话,肯定要把需要保护的城市修在防线内部了。可是A国上层现在还犹豫不决,到底该把哪些城市作为保护对象呢?又由于A国的经费有限,所以希望你能帮忙完成如下的一个任务:

    1.给出你所有的A国城市坐标

    2.A国上层经过讨论,考虑到经济问题,决定取消对i城市的保护,也就是说i城市不需要在防线内了

    3.A国上层询问对于剩下要保护的城市,修建防线的总经费最少是多少

    你需要对每次询问作出回答。注意单位1长度的防线花费为1。

    A国的地形是这样的,形如下图,x轴是一条河流,相当于一条天然防线,不需要你再修建

    A国总是有两个城市在河边,一个点是(0,0),一个点是(n,0),其余所有点的横坐标均大于0小于n,纵坐标均大于0。A国有一个不在(0,0)和(n,0)的首都。(0,0),(n,0)和首都这三个城市是一定需要保护的。

    img

    上图中,A,B,C,D,E点为A国城市,且目前都要保护,那么修建的防线就会是A-B-C-D,花费也就是线段AB的长度+线段BC的长度+线段CD的长度,如果,这个时候撤销B点的保护,那么防线变成下图

    img

    Input

    第一行,三个整数n,x,y分别表示河边城市和首都是(0,0),(n,0),(x,y)。

    第二行,一个整数m。

    接下来m行,每行两个整数a,b表示A国的一个非首都非河边城市的坐标为(a,b)。

    再接下来一个整数q,表示修改和询问总数。

    接下来q行每行要么形如1 i,要么形如2,分别表示撤销第i个城市的保护和询问。

    Output

    对于每个询问输出1行,一个实数v,表示修建防线的花费,保留两位小数

    Sample Input

    4 2 1
    2
    1 2
    3 2
    5
    2
    1 1
    2
    1 2
    2
    

    Sample Output

    6.47
    5.84
    4.47
    

    Solution

    考虑把操作顺序改一下,我们反着做,就变成了维护凸包,支持加点。

    由于是个上凸壳,可以直接用一个(set)维护凸包上的点的(x)坐标。

    然后每次加点(lower\_bound)找到(x)最近的一条边,然后判一下在不在凸包内。

    若不在凸包内,就往两边暴力判满不满足上凸壳性质,若不满足,就删点。

    每个点只会被至多加一次,删一次,时间复杂度(O(nlog n))

    #include<bits/stdc++.h>
    using namespace std;
     
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
      
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
     
    const int maxn = 2e6+10;
     
    struct point {
        int x,y;
        int operator ^ (const point &rhs) const {return x*rhs.y-rhs.x*y;}
        int operator < (const point &rhs) const {return x<rhs.x||(x==rhs.x&&y<rhs.y);}
        point operator - (const point &rhs) const {return (point){x-rhs.x,y-rhs.y};}
    }a[maxn],sta[maxn],r[maxn];
     
    int cnt,op[maxn],w[maxn],vis[maxn],top,m;
     
    double ans;
     
    set<point > s;
     
    #define sqr(x) ((x)*(x))
    double dis(point x,point y) {return sqrt(sqr(x.x-y.x)+sqr(y.y-x.y));}
     
    void make() {
        int num=0;
        for(int i=1;i<=cnt;i++) if(!vis[i]) r[++num]=a[i];
        sort(r+1,r+num+1);sta[++top]=r[1],sta[++top]=r[2];
        for(int i=3;i<=num;i++) {
            while(top>1&&((r[i]-sta[top-1])^(sta[top]-sta[top-1]))<=0) top--;
            sta[++top]=r[i];
        }
        s.insert(sta[1]);
        for(int i=2;i<=top;i++) s.insert(sta[i]),ans+=dis(sta[i],sta[i-1]);
    }
     
    double res[maxn+8];
    int Top;
     
    void solve() {
        for(int i=m;i;i--) {
            if(op[i]==2) res[++Top]=ans;
            else {
                point x=a[w[i]+3];
                set <point > :: iterator it,it2,pre,nxt;
                it=s.lower_bound(x);it--;
                it2=it;it2++;
                if(((x-(*it))^((*it2)-(*it)))>=0) continue;
                ans-=dis(*it,*it2);
                while(it!=s.begin()) {
                    pre=it;pre--;
                    if(((x-(*it))^((*it)-(*pre)))>0) break;
                    ans-=dis(*it,*pre);
                    it--;pre++;s.erase(pre);
                }
                while(it2!=s.end()) {
                    nxt=it2;nxt++;
                    if((((*it2)-x)^((*nxt)-(*it2)))<0) break;
                    ans-=dis(*it2,*nxt);
                    nxt--;it2++;s.erase(nxt);
                }
                it=s.lower_bound(x);
                ans+=dis(x,*it);
                it--,ans+=dis(x,*it);
                s.insert(x);
            }
        }
        for(int i=Top;i;i--) printf("%.2lf
    ",res[i]);
    }
     
    int main() {
        int n,x,y;read(n),read(x),read(y);
        a[++cnt]=(point){0,0};
        a[++cnt]=(point){n,0};
        a[++cnt]=(point){x,y};
        read(n);
        for(int i=1;i<=n;i++) read(x),read(y),a[++cnt]=(point){x,y};
        read(m);
        for(int i=1;i<=m;i++) {
            read(op[i]);if(op[i]==1) read(w[i]),vis[w[i]+3]=1;
        }
        make();solve();
        return 0;
    }
    
  • 相关阅读:
    Heroku
    Git基本命令(转)
    github之从零开发
    物理层、、。。。
    BeautifulSoup, 的使用
    路径设置
    http协议
    Python 的os模块与sys模块
    python 操作MySQL数据库
    多进程记要
  • 原文地址:https://www.cnblogs.com/hbyer/p/10324119.html
Copyright © 2011-2022 走看看