动态凸包

来源:互联网 发布:涟源市私立行知中学 编辑:程序博客网 时间:2024/06/04 23:21

动态凸包

时间限制: 5 Sec 内存限制: 256 MB

题目描述
给出一个点集pset,按顺序将点pi(1<=i<=10^5)加入前i-1个点所形成的凸包中,如果点pi落在了凸包外,更新凸包
对于每一个点pi输出当前形成凸包的面积。初始时,点集pset中有3个点。

样例输入
1 0 0 3 3 2
5
1 2
2 1
3 0
2 3
0 1

样例输出
8
8
12
14
16

题解

本来只想到维护水平序凸包,分别维护上下凸壳即可,然而细节比较多。wbs大爷告诉我可以维护极角序凸包,这样只要写一个凸包(orxwbs!!!)。
用一个平衡树/set维护凸包即可。

代码

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<string>#include<cmath>#include<set>#include<algorithm>#define ll long long#define iter multiset<node>::iteratorusing namespace std;int n;ll S;struct node{  int a,b;double ang;  bool operator<(const node &x)  const{return ang<x.ang||(ang==x.ang&&b<x.b);}  node operator-(const node &x){return (node){a-x.a,b-x.b,ang};}  ll operator*(const node &x){return (ll)a*x.b-(ll)b*x.a;}}t[4],o,p;multiset<node>q;double get(node x){return (double)atan2(x.b,x.a);}iter getpre(iter x){if(x==q.begin())x=q.end();return (--x);}iter getnxt(iter x){return (++x)==q.end()?q.begin():x;}node operator-(iter x,iter y){return (node)*x-(node)*y;}ll operator*(iter x,iter y){return ((node)*x)*((node)*y);}int main(){  for(int i=1;i<=3;i++)  {    scanf("%d%d",&t[i].a,&t[i].b);    o.a+=t[i].a;o.b+=t[i].b;    t[i].a*=3;t[i].b*=3;  }  for(int i=1;i<=3;i++)    t[i].ang=(double)get(t[i]-o),q.insert(t[i]-o);  sort(t+1,t+4);  S=t[1]*t[2]+t[2]*t[3]+t[3]*t[1];  scanf("%d",&n);  while(n--)  {    scanf("%d%d",&p.a,&p.b);    p.a*=3;p.b*=3;p=p-o;p.ang=get(p);    iter nxt=q.lower_bound(p);    if(nxt==q.end())nxt=q.begin();    iter pre=getpre(nxt);    if((nxt-pre)*(p-*pre)<0)    {      S-=pre*nxt;      iter pos=getpre(pre);      while((pre-pos)*(p-*pos)<=0)      {        S-=pos*pre;q.erase(pre);        pre=pos;pos=getpre(pos);      }      pos=getnxt(nxt);      while((nxt-pos)*(p-*pos)>=0)      {        S-=nxt*pos;q.erase(nxt);        nxt=pos;pos=getnxt(pos);      }      S+=p*(*nxt)-(p*(*pre));q.insert(p);    }    printf("%lld\n",S/9);  }  return 0;}
1 0