动态维护凸包

来源:互联网 发布:手机维修网络培训 编辑:程序博客网 时间:2024/05/16 04:37

依次插入n个点,询问凸包面积。

利用granham思想,维护凸包,水平序要维护两个凸壳,比较麻烦,所以用极角序,每次查入用平衡树维护极角离他最近的点,此时到双向链表上开始模拟granham双向删点,直到无法删为止,因为每个点至多删一次,所以是nlogn的复杂度。面积维护用叉积即时维护即可。

依次插入n个半平面,询问半平面交面积。

与上题类似,维护法向量的极角,双向删半平面(当相邻一半平面两交点均在此半平面外即删),实现更复杂,我还没实现。

#include <cstdio>#include <cstdlib>#include <cstring>#include <cmath>#include <ctime>const int maxn=100005,oo=1073741819;struct point{    long long x,y;    double t,d;}a[maxn],o;int n,rt[maxn],r[maxn],l[maxn],id[maxn],ins[maxn],net[maxn];long long sum,s[maxn],ans;void left(int x){    long long y=rt[x],z=rt[y];    r[y]=l[x],rt[l[x]]=y;    l[x]=y,rt[y]=x;    if (r[z]==y) r[z]=x;else l[z]=x;rt[x]=z;}void right(int x){    long long y=rt[x],z=rt[y];    l[y]=r[x],rt[r[x]]=y;    r[x]=y,rt[y]=x;    if (r[z]==y) r[z]=x;else l[z]=x;rt[x]=z;}int cmp(int x,int k){    if ((a[k].t>a[x].t)||((a[k].t==a[x].t)&&(a[k].d>a[x].d))) return -1;    else if ((a[k].t<a[x].t)||((a[k].t==a[x].t)&&(a[k].d<a[x].d))) return 1;    return 0;}long long cross(point e,point r){    return ((e.x*r.y)-(e.y*r.x));}long long cr(int i,int j,int k){    point e;e.x=a[j].x-a[i].x,e.y=a[j].y-a[i].y;    point r;r.x=a[k].x-a[i].x,r.y=a[k].y-a[i].y;    return cross(e,r);}long long dist(point e,point r){    long long x=e.x-r.x,y=e.y-r.y;    return (x*x+y*y);}int ori(int k,int root){    id[k]=rand(),rt[k]=root;return k;}void inser(int k){    int x=0;    for (;;)    {        if (cmp(x,k)==-1)            if (r[x]!=0) x=r[x];else {r[x]=ori(k,x),x=r[x];break;}        else if (cmp(x,k)==1)            if (l[x]!=0) x=l[x];else {l[x]=ori(k,x),x=l[x];break;}        else return ;    }       for (;id[rt[x]]>id[x];)        if (l[rt[x]]==x) right(x);else left(x);}void cancel(int k){    net[ins[k]]=net[k],ins[net[k]]=ins[k];    sum=sum-s[ins[k]]-s[k];    s[ins[k]]=cross(a[ins[k]],a[net[k]]),sum=sum+s[ins[k]];    for (;(l[k])&&(r[k]);)  if (id[l[k]]<id[r[k]])  right(l[k]);else left(r[k]);    int j=(l[k]==0) ? r[k] : l[k];    if (l[rt[k]]==k) l[rt[k]]=j;else r[rt[k]]=j;rt[j]=rt[k];}int find(int k){    int ll=0,x=r[0],pd;    for (;x;)    {     pd=cmp(x,k);        if (pd==-1) ll=(cmp(ll,x)==-1) ? x : ll,x=r[x];      else if (pd==1) x=l[x];      else return x;    }    return ll;}void enter(int k){    a[k].t=atan2(a[k].y-o.y,a[k].x-o.x)*10000,a[k].d=dist(a[k],o);    int i=find(k),j=net[i],flag=0;    if (0==i) {for (;r[i]!=0;i=r[i]) ;j=net[i];}    if (cmp(i,k)==0) return ;    for (;(cr(ins[i],i,k)<=0);cancel(i),i=ins[i],flag=1) ;    if ((1==flag)||(cr(i,k,j)>0))    {        net[k]=net[i],ins[k]=i,ins[net[k]]=k,net[i]=k,inser(k);        sum=sum-s[i],s[i]=cross(a[i],a[k]),s[k]=cross(a[k],a[j]);        sum=sum+s[i]+s[k];           for (i=net[j];(cr(k,j,i)<=0);cancel(j),j=i,i=net[i]) ;    }}void origin(){    int i,j;    point c;    id[0]=-oo,a[0].t=-oo;    for (i=1;i<=3;i++) a[i].t=atan2(a[i].y-o.y,a[i].x-o.x)*10000,a[i].d=dist(a[i],o);    for (i=1;i<=2;i++)        for (j=i+1;j<=3;j++)            if (cmp(i,j)==1) c=a[i],a[i]=a[j],a[j]=c;    net[1]=2,net[2]=3,net[3]=1;    ins[1]=3,ins[2]=1,ins[3]=2;    s[1]=cross(a[1],a[2]),s[2]=cross(a[2],a[3]),s[3]=cross(a[3],a[1]);    sum=s[1]+s[2]+s[3];    inser(1);inser(2);inser(3);}void init(){    int i,j,t,k;    for (i=1;i<=3;o.x+=a[i].x,o.y+=a[i].y,i++) scanf("%d%d",&a[i].x,&a[i].y),a[i].x*=3,a[i].y*=3;    o.x/=3,o.y/=3;    origin();    sum=cross(a[1],a[2])+cross(a[2],a[3])+cross(a[3],a[1]);    scanf("%d\n",&n);    for (i=4;i<=n+3;i++)    {        scanf("%d%d",&a[i].x,&a[i].y),a[i].x*=3,a[i].y*=3;        enter(i);        if (sum<0) ans=-sum/9;else ans=sum/9;        printf("%I64d\n",ans);     }}int main(){    freopen("Convex.in","r",stdin);    freopen("Convex.out","w",stdout);        srand((int)time(NULL));        init();    return 0;}


原创粉丝点击