zoukankan      html  css  js  c++  java
  • 【XSY3141】哲学家 计算几何 线段树

    题目描述

      有一个平面,最开始平面上没有任何点。

      你要按顺序加入 (n) 个点,求加入每个点后有多少三角形严格包含原点(在边界上不算)。

      (nleq 400000),无重点。

    题解

      其实这题本来是强制在线的。

      考虑不满足条件的三个顶点有什么特征。

      先把每个点的极角求出来,可以发现,不满足条件的三个点以及原点组成的扇形的角度 (leq pi)

      那么满足条件的三角形个数就是总的三角形个数减掉不满足条件的三角形个数。

      先把这些点按极角排序,记 (c_i)(i) 右侧弧度范围为 (pi) 以内的点的个数。

      插入一个点 (x) 的时候,找到 (x) 左边 (pi) 范围内最左的点 (y) 以及右边 (pi) 范围内最右的点 (z),贡献就是 (ysim x)(c_i) 之和 (+ xsim z) 中任取两个点的方案数。

      用平衡树/线段树维护即可。

      当两个点的极角之差很小的时候,要用叉积判断大小关系。

      注意三点共线的情况。

      时间复杂度:(O(nlog n))

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    typedef double db;
    typedef long long ll;
    const int N=400010;
    const db eps=1;
    const db pi=acos(-1);
    struct point
    {
    	ll x,y;
    	point(ll a=0,ll b=0):x(a),y(b){}
    };
    point operator -(const point &a,const point &b){return point(a.x-b.x,a.y-b.y);}
    ll operator *(const point &a,const point &b){return a.x*b.y-a.y*b.x;}
    point operator -(const point &a){return point(-a.x,-a.y);}
    point a[N];
    int n;
    db ang[N];
    int e[N];
    struct pp
    {
    	db ang;
    	point a;
    	int id;
    	pp(db x=0,point y=point(),int z=0):ang(x),a(y),id(z){}
    };
    pp f[N];
    int operator <(pp a,pp b)
    {
    	if(fabs(a.ang-b.ang)>eps)
    		return a.ang<b.ang;
    	ll s=a.a*b.a;
    	if(s!=0)
    		return s>0;
    	return a.id<b.id;
    }
    namespace seg
    {
    	int t[1100000];
    	ll s[1100000];
    	int s2[1100000];
    #define ls (p<<1)
    #define rs ((p<<1)|1)
    #define mid ((L+R)>>1)
    	void add(int p,int v)
    	{
    		t[p]+=v;
    		s[p]+=(ll)v*s2[p];
    	}
    	void push(int p)
    	{
    		if(t[p])
    		{
    			add(ls,t[p]);
    			add(rs,t[p]);
    			t[p]=0;
    		}
    	}
    	void add(int p,int l,int r,int v,int L,int R)
    	{
    		if(l<=L&&r>=R)
    		{
    			add(p,v);
    			return;
    		}
    		push(p);
    		if(l<=mid)
    			add(ls,l,r,v,L,mid);
    		if(r>mid)
    			add(rs,l,r,v,mid+1,R);
    		s[p]=s[ls]+s[rs];
    	}
    	void set(int p,int x,int L,int R)
    	{
    		if(L==R)
    		{
    			s2[p]=1;
    			return;
    		}
    		push(p);
    		if(x<=mid)
    			set(ls,x,L,mid);
    		else
    			set(rs,x,mid+1,R);
    		s2[p]=s2[ls]+s2[rs];
    	}
    	ll query1(int p,int l,int r,int L,int R)
    	{
    		if(l<=L&&r>=R)
    			return s[p];
    		push(p);
    		ll res=0;
    		if(l<=mid)
    			res+=query1(ls,l,r,L,mid);
    		if(r>mid)
    			res+=query1(rs,l,r,mid+1,R);
    		return res;
    	}
    	int query2(int p,int l,int r,int L,int R)
    	{
    		if(l<=L&&r>=R)
    			return s2[p];
    		push(p);
    		int res=0;
    		if(l<=mid)
    			res+=query2(ls,l,r,L,mid);
    		if(r>mid)
    			res+=query2(rs,l,r,mid+1,R);
    		return res;
    	}
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("c.in","r",stdin);
    	freopen("c.out","w",stdout);
    #endif
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%lld%lld",&a[i].x,&a[i].y);
    		ang[i]=atan2(a[i].y,a[i].x);
    		if(!a[i].y&&a[i].x<0)
    			ang[i]=-pi;
    	}
    	for(int i=1;i<=n;i++)
    		f[i]=pp(ang[i],a[i],i);
    	sort(f+1,f+n+1);
    	for(int i=1;i<=n;i++)
    		e[f[i].id]=i;
    	int y,z;
    	ll s=0,ans;
    	for(int i=1;i<=n;i++)
    	{
    		if(ang[i]<-eps||(fabs(ang[i])<eps&&a[i]*point(1,0)>0))
    		{
    			y=lower_bound(f+1,f+n+1,pp(ang[i]+pi,-a[i],0))-f;
    			if(y<=n)
    			{
    				s+=seg::query1(1,y,n,1,n);
    				seg::add(1,y,n,1,1,n);
    			}
    			s+=seg::query1(1,1,e[i],1,n);
    			z=upper_bound(f+1,f+n+1,pp(ang[i]+pi,-a[i],n+1))-f-1;
    			if(y<=z)
    			{
    				ll w=seg::query2(1,y,z,1,n);
    				s-=w*(w-1)/2;
    				ll x=seg::query2(1,lower_bound(f+1,f+n+1,pp(ang[i],a[i],0))-f,e[i],1,n);
    				s-=x*w;
    			}
    			ll tmp=seg::query2(1,e[i],z,1,n);
    			s+=tmp*(tmp-1)/2;
    			seg::set(1,e[i],1,n);
    			if(e[i]>1)
    				seg::add(1,1,e[i]-1,1,1,n);
    			seg::add(1,e[i],e[i],tmp,1,n);
    		}
    		else
    		{
    			y=lower_bound(f+1,f+n+1,pp(ang[i]-pi,-a[i],0))-f;
    			s+=seg::query1(1,y,e[i],1,n);
    			z=upper_bound(f+1,f+n+1,pp(ang[i]-pi,-a[i],n+1))-f-1;
    			if(y<=z)
    			{
    				ll w=seg::query2(1,y,z,1,n);
    				s-=w*(w-1)/2;
    				ll x=seg::query2(1,lower_bound(f+1,f+n+1,pp(ang[i],a[i],0))-f,e[i],1,n);
    				s-=x*w;
    			}
    			ll tmp=0;
    			if(z>0)
    				tmp+=seg::query2(1,1,z,1,n);
    			tmp+=seg::query2(1,e[i],n,1,n);
    			s+=tmp*(tmp-1)/2;
    			seg::set(1,e[i],1,n);
    			if(e[i]>y)
    				seg::add(1,y,e[i]-1,1,1,n);
    			seg::add(1,e[i],e[i],tmp,1,n);
    		}
    		ans=(ll)i*(i-1)*(i-2)/6-s;
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Uva 10779 collector's problem
    poj 2728 最优比率树(最小生成树问题)
    LA 3126 二分图匹配 最小路径覆盖
    poj 1149 最大流构图
    Step By Step(Java XML篇)
    Step By Step(Java 输入输出篇)
    Step By Step(Java 集合篇)
    Step By Step(Java 线程篇)
    Step By Step(Java 反射篇)
    Step By Step(Java 国际化篇)
  • 原文地址:https://www.cnblogs.com/ywwyww/p/9267491.html
Copyright © 2011-2022 走看看