[BZOJ2300][HAOI2011][动态凸包]防线修建

来源:互联网 发布:人工智能 技术论坛 编辑:程序博客网 时间:2024/05/18 01:38
[Problem 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,纵坐标均大于0A国有一个不在(0,0)(n,0)的首都。(0,0),(n,0)和首都这三个城市是一定需要保护的。

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

[Algorithm & Data Structure]
动态凸包
[Analysis]
明显的动态凸包(其实暴力凸包也可以过)。删点比较不好搞,所以倒着算,先把所有删掉的点去掉,然后一个个往里面加。动态凸包写Splay比较蛋疼……
[Code]
/**************************************************************    Problem: 2300    User: gaotianyu1350    Language: C++    Result: Accepted    Time:620 ms    Memory:7640 kb****************************************************************/ #include <cstdio>#include <cstring>#include <cmath>#include <cstdlib>#include <iostream>using namespace std; const int MAXN = 100100;const int MAXQ = 200100; class splay_node{public:    splay_node *ch[2], *pre;    int x, y, cnt;    splay_node();     bool operator < (const splay_node b) const    {        return (x == b.x && y < b.y) || x < b.x;    }     bool operator == (const splay_node b) const    {        return (x == b.x && y == b.y);    }     int Which()    {        return pre->ch[0] == this ? 0 : 1;    }     void Set(splay_node *child, int wh)    {        ch[wh] = child, child->pre = this;    } } splay[MAXN]; int tot = 0;splay_node *root; splay_node::splay_node(){    ch[0] = ch[1] = pre = splay;    x = 0;    y = 0;    cnt = 1;} inline void Rotate(splay_node *now){    splay_node *oldfather = now->pre;    splay_node *grand = now->pre->pre;    int wh = now->Which();    oldfather->Set(now->ch[wh ^ 1], wh);    now->Set(oldfather, wh ^ 1);    now->pre = grand;    if (grand != splay)        grand->ch[grand->ch[0] == oldfather ? 0 : 1] = now;} inline void Splay(splay_node *now, splay_node *tar){    for (; now->pre != tar; Rotate(now))        if (now->pre->pre != tar)            now->Which() == now->pre->Which() ? Rotate(now->pre) : Rotate(now);    if (tar == splay)        root = now;} inline splay_node *Find(int x, int y){    splay_node tar;    tar.x = x, tar.y = y;    splay_node *now = root;    while (now != splay)    {        if (*now == tar) return now;        if (tar < *now)            now = now->ch[0];        else            now = now->ch[1];    }    return now;} inline splay_node *GetPre(splay_node *now){    Splay(now, splay);    for (now = now->ch[0]; now->ch[1] != splay; now = now->ch[1]);    return now;} inline splay_node *GetNext(splay_node *now){    Splay(now, splay);    for (now = now->ch[1]; now->ch[0] != splay; now = now->ch[0]);    return now;} inline splay_node *NewNode(int x, int y){    tot++;    splay[tot].x = x, splay[tot].y = y;    return splay + tot;} inline splay_node *Add(int x, int y){    splay_node tar;    tar.x = x, tar.y = y;    splay_node *now = root;    splay_node *last = splay;     if (root == splay)    {        root = NewNode(x, y);        return root;    }     while (now != splay)    {        last = now;        if (*now == tar)        {            now->cnt++;            return now;        }        if (tar < *now)            now = now->ch[0];        else            now = now->ch[1];    }     now = NewNode(x, y);    if (tar < *last)        last->Set(now, 0);    else        last->Set(now, 1);    Splay(now, splay);    return now;} inline void Delete(splay_node *now = splay, int x = 0, int y = 0){    if (now == splay)        now = Find(x, y);    if (now->cnt > 1)    {        now->cnt--;        return;    }    Splay(now, splay);    if (now->ch[0] == splay && now->ch[1] == splay)    {        root = splay;        return;    }    if (now->ch[0] == splay || now->ch[1] == splay)    {        root = now->ch[0] == splay ? now->ch[1] : now->ch[0];        root->pre = splay;        return;    }    splay_node *_pre = GetPre(root);    Splay(_pre, root);    _pre->Set(root->ch[1], 1);    root = _pre;    root->pre = splay;} int n, x, y, m;int query;int xx[MAXN], yy[MAXN];bool check[MAXN] = { 0 }; struct QueryData{    int k, x;    double ans;} qd[MAXQ]; double nowans; inline double dis(int x1, int y1, int x2, int y2){    return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));} inline double dis(splay_node *a, splay_node *b){    return dis(a->x, a->y, b->x, b->y);} inline int cross(splay_node *a, splay_node *b, splay_node *c){    return (b->x - a->x) * (c->y - b->y) - (c->x - b->x) * (b->y - a->y);} inline bool isstart(splay_node *now){    return (now->x == 0 && now->y == 0);} inline bool isend(splay_node *now){    return (now->x == n && now->y == 0);} inline void AddACity(int x, int y){    splay_node *now = Add(x, y);    splay_node *_pre = GetPre(now);    splay_node *_next = GetNext(now);    if (cross(_pre, now, _next) >= 0)    {        Delete(now);        return;    }    nowans -= dis(_pre, _next);    if (!isstart(_pre))        for (splay_node *_prepre = GetPre(_pre); cross(_prepre, _pre, now) >= 0;)        {             nowans -= dis(_pre, _prepre);             Delete(_pre);             _pre = _prepre;             if (isstart(_pre)) break;             _prepre = GetPre(_pre);        }    if (!isend(_next))        for (splay_node *_nextnext = GetNext(_next); cross(now, _next, _nextnext) >= 0;)        {             nowans -= dis(_next, _nextnext);             Delete(_next);             _next = _nextnext;             if (isend(_next)) break;             _nextnext = GetNext(_next);        }    nowans += dis(now, _pre) + dis(now, _next);} int main(){    //freopen("input.txt", "r", stdin);    scanf("%d%d%d", &n, &x, &y);    root = splay;    Add(0, 0);    Add(n, 0);    Add(x, y);    nowans = dis(0, 0, x, y) + dis(x, y, n, 0);    scanf("%d", &m);    for (int i = 1; i <= m; i++)        scanf("%d%d", &xx[i], &yy[i]);    scanf("%d", &query);    for (int i = 1; i <= query; i++)    {        scanf("%d", &qd[i].k);        if (qd[i].k == 1)        {            scanf("%d", &qd[i].x);            check[qd[i].x] = true;        }    }    for (int i = 1; i <= m; i++)        if (!check[i]) AddACity(xx[i], yy[i]);    for (int i = query; i >= 1; i--)        if (qd[i].k == 1)            AddACity(xx[qd[i].x], yy[qd[i].x]);        else            qd[i].ans = nowans;    for (int i = 1; i <= query; i++)        if (qd[i].k == 2)            printf("%.2f\n", qd[i].ans);}


0 0
原创粉丝点击