动态凸包问题

对于动态凸包添加的问题的一般做法:

动态凸包问题

 

  如上图。我们知道,如果能够有一种数据结构可以维护一下凸包上的顶点与原点的角度,对于插入一个点now的时候,我们就可以二分出点的位置,然后找到比他角度小的上一个顶点pre以及比他角度大的下一个顶点next,通过判断now跟next,pre的叉积正负来判断点now是否在凸包内。

  对于需要插入不在凸包中的点时,我们找出了pre,next之后,需要分别通过维护上凸包以及下凸包,把多余的点从平衡树中删掉。例如上图中,由于next_next可以被now“看见”,所以next需要被删掉,删掉next之后继续判断next_next是否需要删掉,直到不能够删掉为止。对于下凸包同样进行这样的操作。

  由于我们使用atan2(y,x)这样的方式来维护极角序,不可避免的存在极角相同的情况,可能存在精度误差使得找出的pre,next不是真正意义上的pre,next,所以我们需要在插入前三个点的时候用随机数乘上三个点的坐标,然后以该坐标的加权平均数作为原点。具体可以看代码。

  如果可以用long long,最好直接用long long表示点的坐标,因为用double的精度可能不够,而判断叉积正负的时候可以直接用原坐标来判断。

 

 CF 70 D. Professor's task

题目:

现在有两种操作:
1.把(x,y)加到凸包中
2.问(x,y)是否在凸包中
现在给出n个操作,对于操作二,输出

分析:

这题的数据比较强,所以强烈推荐做一下。

#include <set>

#include <map>

#include <cmath>

#include <queue>

#include <stack>

#include <string>

#include <vector>

#include <cstdio>

#include <cstring>

#include <iostream>

#include <algorithm>



using namespace std;



typedef long long ll;

typedef unsigned long long ull;



#define debug puts("here")

#define rep(i,n) for(int i=0;i<n;i++)

#define rep1(i,n) for(int i=1;i<=n;i++)

#define REP(i,a,b) for(int i=a;i<=b;i++)

#define foreach(i,vec) for(unsigned i=0;i<vec.size();i++)

#define pb push_back

#define RD(n) scanf("%d",&n)

#define RD2(x,y) scanf("%d%d",&x,&y)

#define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z)

#define RD4(x,y,z,w) scanf("%d%d%d%d",&x,&y,&z,&w)

#define All(vec) vec.begin(),vec.end()

#define MP make_pair

#define PII pair<int,int>



/******** program ********************/



const double eps = 1e-8;



double ox,oy;



struct node{

    int x,y;

    double angle;

    int op;

    friend bool operator < (node a,node b){

        return a.angle-b.angle<0;

    }

    inline void rd(){

        scanf("%d%d%d",&op,&x,&y);

    }

    inline void ch(){

        angle = atan2(y-oy,x-ox);

    }

    inline void od(){

        cout<<op<<" "<<x<<" "<<y<<" "<<atan2(y,x)<<endl;

    }

};



set<node> s;



inline node getPre(node now){ // 得到前驱

    if(s.count(now)>0)

        return now;

    set<node>::iterator it = s.lower_bound(now );

    if(it==s.begin())

        it = s.end();

    return *--it;

}



inline node getNext(node now){ // 得到后继

    set<node>::iterator it = s.upper_bound( now );

    if(it==s.end())

        it = s.begin();

    return *it;

}



inline ll det(node a,node b,node o){

    return ll(a.x-o.x)*(b.y-o.y)-ll(b.x-o.x)*(a.y-o.y);

}



inline bool in(node now){ // 判断点是否在凸包内

    if(s.size()<3)

        return false;

    node p = getPre(now);

    node n = getNext(now);

    return det(p,n,now)>=0;

}



inline void add(node now){ // 添加

    if(in(now)) return;



    while(1){

        node n = getNext(now);

        s.erase(n);

        node nn = getNext(now);

        if(det(now,nn,n)<0){

            s.insert(n);

            break;

        }

    }



    while(1){

        node p = getPre(now);

        s.erase(p);

        node pp = getPre(now);

        if(det(pp,now,p)<0){

            s.insert(p);

            break;

        }

    }

    s.insert(now);

}



int main(){



#ifndef ONLINE_JUDGE

	freopen("sum.in","r",stdin);

	//freopen("sum.out","w",stdout);

#endif



    int n;

    while(~RD(n)){

        node a[5];

        ox = oy = 0;

        double t[] = {0,0.49214632134, 0.2348329743213, 0.9854827427182};

        double sum = 0;

        rep1(i,3){

            a[i].rd();

            ox += a[i].x*t[i];

            oy += a[i].y*t[i];

            sum += t[i];

        }



        s.clear();

        ox /= sum, oy /= sum;



        rep1(i,3){

            a[i].ch();

            s.insert(a[i]);

        }



        node now;

        n -= 3;

        while(n--){

            now.rd();

            now.ch();

            if(now.op==1)

                add(now);

            else

                in(now)?puts("YES"):puts("NO");

        }

    }



	return 0;

}

  

SUG 277 Heros

题目:

先给出三个点,保证三个点不共线。
现在添加k个点,问添加第i个点时,现有的点所形成的凸包面积的两倍

分析:

动态凸包添加点计算面积的问题。
我们先判断点是否在凸包内。
不在的话,把三角形(next,pre,now)加上。
然后对于上半部分,判断next是否需要删掉,需要删掉的话,面积加上三角形(next,next_next,now),
继续判断下一个点。
对于下半部分进行同样的操作即可。

 

 

#include <set>

#include <map>

#include <cmath>

#include <queue>

#include <stack>

#include <string>

#include <vector>

#include <cstdio>

#include <cstring>

#include <iostream>

#include <algorithm>



using namespace std;



typedef long long ll;

typedef unsigned long long ull;



#define debug puts("here")

#define rep(i,n) for(int i=0;i<n;i++)

#define rep1(i,n) for(int i=1;i<=n;i++)

#define REP(i,a,b) for(int i=a;i<=b;i++)

#define foreach(i,vec) for(unsigned i=0;i<vec.size();i++)

#define pb push_back

#define RD(n) scanf("%d",&n)

#define RD2(x,y) scanf("%d%d",&x,&y)

#define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z)

#define RD4(x,y,z,w) scanf("%d%d%d%d",&x,&y,&z,&w)

#define All(vec) vec.begin(),vec.end()

#define MP make_pair

#define PII pair<int,int>



/******** program ********************/



ll area;



struct node{

    ll x,y;

    double ang;



    node(){}

    node(ll _x,ll _y):x(_x),y(_y){}

    node(ll _x,ll _y,double _a):x(_x),y(_y),ang(_a){}



    void rd(){

        int _x,_y;

        RD2(_x,_y);

        x = _x;

        y = _y;

    }



    void od(){

        cout<<x<<" "<<y<<" "<<ang<<endl;

    }



    friend bool operator < (node a,node b){

        return a.ang<b.ang;

    }



    friend node operator - (node a,node b){

        return node(a.x-b.x,a.y-b.y);

    }

};



set<node> s;



ll det(node a,node b){

    return a.x*b.y-a.y*b.x;

}



ll det(node a,node b,node o){

    return det(a-o,b-o);

}



node getPre(node now){

    if(s.count(now)>0)

        return now;

    set<node>::iterator it = s.lower_bound(now);

    if(it==s.begin())

        it = s.end();

    return *--it;

}



node getNext(node now){

    set<node>::iterator it = s.upper_bound(now);

    if(it==s.end())

        it = s.begin();

    return *it;

}



bool in(node now){

    node p = getPre(now);

    node n = getNext(now);

    return det(now,n,p)<=0;

}



void add(node now){

    if(in(now)) return;

    area += abs( det(now,getNext(now),getPre(now)) );

    while(true){

        node p = getPre(now);

        s.erase(p);

        node pp = getPre(now);

        if(det(now,pp,p)>=0){

            s.insert(p);

            break;

        }

        area += abs(det(now,pp,p));

    }



    while(true){

        node n = getNext(now);

        s.erase(n);

        node nn = getNext(now);

        if(det(now,nn,n)<=0){

            s.insert(n);

            break;

        }

        area += abs(det(n,nn,now));

    }



    s.insert(now);

}



int main(){



#ifndef ONLINE_JUDGE

	freopen("sum.in","r",stdin);

	//freopen("sum.out","w",stdout);

#endif



    node a[5];

    double t[] = {0.49214632134, 0.2348329743213, 0.9854827427182};

    double sum = 0;

    double ox = 0 , oy = 0;



    rep(i,3){

        a[i].rd();

        ox += a[i].x*t[i];

        oy += a[i].y*t[i];

        sum += t[i];

    }

    ox /= sum;

    oy /= sum;



    s.clear();

    rep(i,3)

        s.insert(node(a[i].x,a[i].y,atan2(a[i].y-oy,a[i].x-ox)));

    area = abs( det(a[0],a[1],a[2]) );



    int n;

    RD(n);

    int x,y;

    rep(i,n){

        RD2(x,y);

        add( node(x,y,atan2(y-oy,x-ox)) );

        printf("%I64d\n",area);

    }



	return 0;

}

  

 

你可能感兴趣的:(动态)