花了些时间准备acm的比赛,现在比赛结束有一段时间了,忙着上自习、做实验。有空就看看linux的书,至于算法,很久没有碰了。昨天刚想回toj做几个题,想不到传来toj系统维护的消息。

回顾比赛,计算几何的东西基本没有用到,这个不过这个模板上的线段树还是发挥了点作用。把模板传上来,算是一个阶段性的总结。也希望大牛多给我指出些不对的地方。


  *常量定义
  */
 
const double INF=1e200;
 
const double EPS=1e-7;
 
const double PI =acos(-1);

 
/*
  *点的定义
  
*/
 
struct PT
 {
     
double x,y;
     PT(){}
     PT(
double xx,double yy)//构造函数
     {
         x
=xx,y=yy;
         
return;
     }
 };

 
/*
  *线段的定义
  
*/
 
struct SEG
 {
     PT st,end;
     
int len;
 };

 
/*
  *圆的定义
  
*/
 
struct CIR
 {
     
double x,y,r;
     CIR(){}
     CIR(
double xx,double yy,double rr)
     {
         x
=xx,y=yy,r=rr;
         
return;
     }
 };

 
/*
  *符号函数
  
*/
 inline 
int sign(double a)
 {
     
if(fabs(a)<EPS)
         
return 0;
     
return a>EPS?1:-1;
 }

 
/*
  *叉积
  
*/
 inline 
int crossP(PT &a,PT &b,PT &c)
 
//cross product of ab and ac
 {
     
return (c.x-a.x)*(b.y-a.y)-(b.x-a.x)*(c.y-a.y);
 }
 inline 
double crossP2(const PT &a,const PT &b,const PT &c,const PT &d)
 
//cross product of ab and cd
 {
     
return (b.x-a.x)*(d.y-c.y)-(b.y-a.y)*(d.x-c.x);
 }

 
/*
  *点积
  
*/
 inline 
double dotP(PT &a,PT &b,PT &c)
 {
     
return (c.x-a.x)*(b.x-a.x)+(c.y-a.y)*(b.y-a.y);
 }

 
/*
  *两点间距离
  
*/
 inline 
int dis(PT a,PT b)
 {
     
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
 }

 
/*
  *点到线段的距离
  
*/
 
double dis2seg(PT pt,PT st,PT end)
 {
     
if(dotP(st,end,pt)*dotP(end,st,pt)<0)
         
return min(dis(pt,st),dis(pt,end));
     
return fabs(crossP(st,end,pt)/dis(st,end));
 }

 
/*
  *已知圆上三点求该圆
  *pt1,pt2,pt3是圆上三点
  *cen是圆心的引用,返回半径
  
*/
 
double getRadiusBy3PT(PT pt1,PT pt2,PT pt3,PT &cen)
 {
     
double a1,a2,b1,b2,c1,c2;
     a1
=2*(pt2.x-pt1.x);
     a2
=2*(pt3.x-pt1.x);
     b1
=2*(pt2.y-pt1.y);
     b2
=2*(pt3.y-pt1.y);
     c1
=pt2.x*pt2.x+pt2.y*pt2.y-pt1.x*pt1.x-pt1.y*pt1.y;
     c2
=pt3.x*pt3.x+pt3.y*pt3.y-pt1.x*pt1.x-pt1.y*pt1.y;
     cen.y
=(a2*c1-a1*c2)/(a2*b1-a1*b2);
     cen.x
=(b2*c1-b1*c2)/(b2*a1-b1*a2);
     
return dis(pt1,c);
 }

 
/*
  *两圆相交部分的面积
  *不相交返回0
  
*/
 
double CircleIntersectionArea(CIR a,CIR b)
 {
     
double len=dis(a,b);
     
if(sign(len-a.r-b.r)>=0 || a.r<EPS || b.r< EPS)
         
return 0;
     
else if(sign(a.r+len-b.r)<=0)
         
return PI*a.r*a.r;
     
else if(sign(b.r+len-a.r)<=0)
         
return PI*b.r*b.r;
     
double ang1=2*acos((a.r*a.r+len*len-b.r*b.r)/(2*a.r*len));
     
double ang2=2*acos((b.r*b.r+len*len-a.r*a.r)/(2*b.r*len));
     
double re=a.r*a.r*ang1*0.5-0.5*a.r*a.r*sin(ang1);
     re
+=b.r*b.r*ang2*0.5-0.5*b.r*b.r*sin(ang2);
     
return re;
 }


 
/*
  *判断线段是否相交
  *端点相交返回false
  *如果需要,把<改为<=
  *那么,共线也会返回true
  
*/
 inline 
bool intersect(PT s1,PT e1,PT s2,PT e2)
 {
     
return((max(s1.x,e1.x)>=min(s2.x,e2.x)) &&
            (max(s2.x,e2.x)
>=min(s1.x,e1.x)) &&
            (max(s1.y,e1.y)
>=min(s2.y,e2.y)) &&
            (max(s2.y,e2.y)
>=min(s1.y,e1.y)) &&
            (crossP(s1,e1,s2)
*crossP(s1,e1,e2)<0&&
            (crossP(s2,e2,s1)
*crossP(s2,e2,e1)<0));
 }

 
/*
   判断线段是否严格相交
 
*/
 
int strictcross(point p1, point p2, point p3, point p4) {
     T a, b, c, d;
     a
=(p3.y-p2.y)*(p1.x-p2.x)-(p1.y-p2.y)*(p3.x-p2.x);
     b
=(p4.y-p2.y)*(p1.x-p2.x)-(p1.y-p2.y)*(p4.x-p2.x);
     c
=(p1.y-p4.y)*(p3.x-p4.x)-(p3.y-p4.y)*(p1.x-p4.x);
     d
=(p2.y-p4.y)*(p3.x-p4.x)-(p3.y-p4.y)*(p2.x-p4.x);
     
return a*b<0 && c*d<0;
 }

 
/*
  *判断简单多边形是否是凸多边形
  *vpt[]:所有点
  *n:点的数量
  
*/
 
bool isprotude(PT vpt[],int n)
 {
     
int t,tt,pre;
     
for(t=0;t<n;t++)
     {
         tt
=0;
         
while(pre=sign(crossP(vpt[t],vpt[(t+1)%n],vpt[(t+2+tt)%n])),pre==0)
             tt
++;
         
for(;tt<n-2;tt++)
         {
             
double d=crossP(vpt[t],vpt[(t+1)%n],vpt[(t+2+tt)%n]);
             
if(sign(d)==0)
                 
continue;
             
if(sign(d)!=pre)
                 
return false;
         }
     }
     
return true;
 }

 
/*
  *判断点是否在凸多边形内部
  *在边上为false
  *for convex polygen only!
  
*/
 
bool inPoly(PT vpt[],int n,PT &pt)
 {
     
int t;
     PT st,end;
     
int dr=sign(crossP(vpt[0],vpt[1],pt));
     
for(t=1;t<n;t++)
     {
         st
=vpt[t];
         end
=vpt[(t+1)%n];
         
if(sign(crossP(st,end,pt))!=dr)
             
return false;
     }
     
return true;
 }

 
/*
  *Graham法求凸包
  *双链法扫描
  *pt[]:所有点
  *n:pt[]中点的个数
  *ans[]:用于返回凸包中的点
  *返回凸包中点的个数
  *默认逆时针时针方向
  
*/
 
int graham(int n,PT pt[],PT ans[])
 {
     
int stk[MAX];
     
bool vis[MAX];
     
int t,p,ps,pans=0;
     sort(pt,pt
+n,cmp);
     memset(vis,
false,sizeof(vis));
     stk[
0]=0;
     stk[
1]=1;
     vis[
1]=true;
     ps
=p=2;
     
while(p<n)
     {
         
if(ps<2 || crossP(pt[stk[ps-2]],pt[stk[ps-1]],pt[p])>=0)
             
//or crossP()<=0 to be clockwise
             
//if points in stk is not enough
             
//or pt[p] is on the left side or on segmemt
             
//push pt[p] into stack 
             
//and mark pt[p] as visited
         {
             stk[ps
++]=p++;
             vis[p]
=true;
         }
         
else
             
//pop the top point 
             
//and mark it as unvisited
             vis[stk[--ps]]=false;
     }
     
for(t=0;t<ps;t++)
         ans[pans
++]=pt[stk[t]];
     
     vis[n
-1]=false;//second travle start here
     ps=0;//clear the stack to start new travle
     
     
for(p=n-1;p>=0;p--)
         
if(!vis[p])
         {
             stk[ps
++]=p;
             
if(ps==2)//push first 2 points
                 break;
         }
     p
--;//next point 
     while(p>=0)//mark is not needed any more
     {
         
if(vis[p])
         {
             p
--;
             
continue;
         }
         
if(ps<2 || crossP(pt[stk[ps-2]],pt[stk[ps-1]],pt[p])>=0)
             
//or crossP()<=0 to be clockwise
             stk[ps++]=p--;
         
else
             
--ps;
     }
     
for(t=1;t<ps-1;t++)
         ans[pans
++]=pt[stk[t]];
     
return pans;
 }
 
/*
   旋转卡壳求最远点距离
  
*/
 
double RotatingCaliper(const int &n,PT pt[])
 {   
     
double re=0;
     
int t=0,tt=1;
     
while(sign(crossP2(pt[t],pt[t+1],pt[tt],pt[tt+1]))==1)
         tt
++;
     
while);<=n)
     {
         
int tmp=sign(crossP2(pt[t%n],pt[(t+1)%n],pt[tt%n],pt[(tt+1)%n]));
         
if(tmp==1)
             tt
=(tt+1)%n;
         
else if(tmp==-1)
             t
++;
         
else
         {
             t
++;
             
continue;
         }
         
double d=dis(pt[t],pt[tt]);
         
if(d>re)
             re
=d;
     }
     
return re;
 }

 
/*
  *线段树,离散化
  
*/
 
struct Line
 {
     
double x,tp,bt;
     
bool  left;
 }line[
2005];
 
double y[2005];
 
int num,ny;//离散化前后y[]的大小
 inline int find(double a)//二分查找对应的离散值
 {
     
int low=0,high=ny-1,mid;
     
while(low<=high)
     {   
         mid
=(low+high)/2;
         
if(a==y[mid])
             
return mid;
         
else if(a<y[mid])
             high
=mid;
         
else
             low
=mid+1;
     }
     
return -1;
 }

 
struct node
 {
     
int st,end,c;//c是区间被覆盖次数
     double m;//m是测度
     node *ls,*rs;
 }
* root;

 node 
* build(int st,int end)
 {
     node 
*p=new node;
     p
->st=st;
     p
->end=end;
     p
->c=0;
     p
->m=0;
     
if(st+1<end)//注意一下这里
     {
         
int mid=(st+end)/2;
         p
->ls=build(st,mid);
         p
->rs=build(mid,end);
     }
     
else
         p
->ls=p->rs=NULL;
     
return p;
 }
 
void init(node *p)//初始化
 {
     p
->c=0;
     p
->m=0;
     
if(p->ls!=NULL)
         init(p
->ls);
     
if(p->rs!=NULL)
         init(p
->rs);
     
return;
 }
 inline 
void update(node *p)//更新测度
 {
     
if(p->c>0)
         p
->m=y[p->end]-y[p->st];
     
else if(p->st+1==p->end)
         p
->m=0;
     
else        
         p
->m=p->ls->m+p->rs->m;
     
return;
 }

 
void ins(node *p,int st,int end)
 {
     
if(st<=p->st && p->end<=end)
     {
         p
->c++;
         update(p);
         
return;
     }
     
int mid=(p->st + p->end)/2;
     
if(p->ls!=NULL)
     {
         ins(p
->ls,st,end);
         update(p);
     }
     
if(p->rs!=NULL)
     {
         ins(p
->rs,st,end);
         update(p);
     }
     
return;
 }
 
void del(node *p,int st,int end)
 {
     
if(st<=p->st && p->end<=end)
     {
         p
->c--;
         update(p);
         
return;
     }
     
if(p->ls!=NULL)
     {
         del(p
->ls,st,end);
         update(p);
     }
     
if(p->rs!=NULL )
     {
         del(p
->rs,st,end);
         update(p);
     }
     
return;
 }

 
/*
  *树状数组,有待完善
  
*/
 
const int MAX=32005*3;//大一点好
 struct node
 {
     
int st,end,c;
 }T[MAX];
 inline 
int ls(int k)
 {
     
return 2*k;
 }
 inline 
int rs(int k)
 {
     
return 2*k+1;
 }
 
void build(int p,int st,int end)//建树
 {
     T[p].st
=st;
     T[p].end
=end;
     T[p].c
=0;
     
if(st<end)
     {
         
int mid=(st+end)/2;
         build(ls(p),st,mid);
         build(rs(p),mid
+1,end);
     }
     
return;
 }
 
void ins(int p,int k)//插入一个点
 {
     
if(T[p].st<=&& k<=T[p].end)
     {
         T[p].c
++;
         
if(T[p].st<T[p].end)
         {
             ins(ls(p),k);
             ins(rs(p),k);
         }
     }
     
return;
 }
 
int ask(int p,int st,int end)//询问一个区间内有几个点
 {
     
if(st<=T[p].st && T[p].end<=end)
         
return T[p].c;
     
else if(st>T[p].end || end<T[p].st)
         
return 0;
     
else
         
return ask(ls(p),st,end)+ask(rs(p),st,end);
 }

 

相关文章: