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;
    }
    
  • 相关阅读:
    bzoj2395: [Balkan 2011]Timeismoney
    bzoj2725: [Violet 6]故乡的梦&&bzoj4400: tjoi2012 桥
    bzoj3047: Freda的传呼机&bzoj2125: 最短路
    bzoj2734: [HNOI2012]集合选数
    bzoj2728: [HNOI2012]与非
    bzoj2730: [HNOI2012]矿场搭建
    bzoj2727: [HNOI2012]双十字
    蓝桥杯-计蒜客之节假日
    蔡基姆拉尔森计算公式
    最长公共子串与最长公共子序列
  • 原文地址:https://www.cnblogs.com/ywwyww/p/9267491.html
Copyright © 2011-2022 走看看