记录编号 275928 评测结果 AAAAAAAAAA
题目名称 [USACO Open09] 牛类刺绣 最终得分 100
用户昵称 GravatarSatoshi 是否通过 通过
代码语言 C++ 运行时间 0.486 s
提交时间 2016-07-03 13:55:33 内存使用 9.66 MiB
显示代码纯文本
#include <fstream>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
#include <map>
#include <cstring>
#define N 100010
using namespace std;
typedef long long ll;
typedef double ld;
ifstream cin("cowemb.in");
ofstream cout("cowemb.out");
int n;
ld R;
const ld eps=1e-10,pi=acos(-1.0);
class segment//改段求段的线段树 
{
	public:
		int seg[4*N];
		int inc[4*N];
		void clear()
		{
			memset(seg,0,sizeof(seg));
			memset(inc,0,sizeof(inc));
		}
		void pushup(int o)
		{
			seg[o]=seg[o<<1]+seg[o<<1|1];
		}
		void pushdown(int o,int l,int r)
		{
			if(l==r||!inc[o])return ;
			int lc=o<<1,rc=lc|1,mid=(l+r)>>1;
			seg[lc]+=inc[o]*(mid-l+1);
			seg[rc]+=inc[o]*(r-mid);
			inc[lc]+=inc[o];
			inc[rc]+=inc[o];
			inc[o]=0;
		}
		void add(int o,int l,int r,int ql,int qr,int val)
		{
			if(ql<=l&&r<=qr)
			{
				seg[o]+=val*(r-l+1);
				inc[o]+=val;
				return ;
			}
			pushdown(o,l,r);
			int mid=(l+r)>>1;
			if(ql<=mid)add(o<<1,l,mid,ql,qr,val);
			if(mid<qr)add(o<<1|1,mid+1,r,ql,qr,val);
			pushup(o);
		}
		int query(int o,int l,int r,int ql,int qr)
		{
			if(ql<=l&&r<=qr)return seg[o];
			int mid=(l+r)>>1;
			int sum=0;
			pushdown(o,l,r);
			if(ql<=mid)sum=sum+query(o<<1,l,mid,ql,qr);
			if(mid<qr)sum=sum+query(o<<1|1,mid+1,r,ql,qr);
			return sum;
		}
}S;
class interval//区间 
{
public:
	ld l,r;	
}A[N],B[N];
bool operator <(interval a,interval b)//排序按左端点排序 
{
	if(a.l==b.l)return a.r<b.r;
	return a.l<b.l;
}
/*离散化专用*/
map<ld,ld> F;
ld C[2*N],D[2*N];
bool vis[2*N]={0};
void lisanhua()//区间的左、右端点对于左右端点的并数列离散化 
{
	int i,m=0;
	memset(vis,0,sizeof(vis));
	memset(C,0,sizeof(C));
	memset(D,0,sizeof(D));
	F.clear();
	for(i=1;i<=n;i++)C[i]=A[i].l;
	for(i=1;i<=n;i++)C[n+i]=A[i].r;
	sort(C+1,C+2*n+1);
	for(i=1;i<2*n;i++)if(C[i]==C[i+1])vis[i]=1;
	for(i=1;i<=2*n;i++)if(!vis[i])D[++m]=C[i];
	for(i=1;i<=m;i++)F[D[i]]=i;
	for(i=1;i<=n;i++)A[i].l=F[A[i].l];
	for(i=1;i<=n;i++)A[i].r=F[A[i].r];
}
void read()
{
	int i,tot=0;
	ld a,b,c,x1,y1,x2,y2,the1,the2;
	cin>>n>>R;
	for(i=1;i<=n;i++)
	{
		cin>>a>>b>>c;
		if(fabs(c)/sqrt(a*a+b*b)>=R)continue;//圆与直线相离,删除 
		/*计算圆与直线的交点(x1,y1)和(x2,y2)*/ 
		x1=(-a*c+sqrt(a*a*c*c+(b*b*R*R-c*c)*(a*a+b*b)))/(a*a+b*b);
	    x2=(-a*c-sqrt(a*a*c*c+(b*b*R*R-c*c)*(a*a+b*b)))/(a*a+b*b);
	    y1=(-b*c+sqrt(b*b*c*c+(a*a*R*R-c*c)*(a*a+b*b)))/(a*a+b*b);
	    y2=(-b*c-sqrt(b*b*c*c+(a*a*R*R-c*c)*(a*a+b*b)))/(a*a+b*b);
	    if(fabs(a*x1+b*y1+c)>eps)swap(y1,y2);
	    /*计算两个交点相对于原点的极角*/
	    the1=atan2(y1,x1);
	    the2=atan2(y2,x2);
	    /*由atan2转化为真正的极角*/
	    if(the1<0)the1+=2*pi;
	    if(the2<0)the2+=2*pi;
	    /*取劣弧,且使区间的左端点在右端点的逆时针方向*/
	    if(the1>the2)swap(the1,the2);
	    if(the2-the1>pi)swap(the1,the2);
	    tot++;
	    /*为了方便观察,由弧度制转化为角数制*/
	    B[tot].l=the1*180/pi;
		B[tot].r=the2*180/pi;
	}
	n=tot;
}
int upperbound(int l,int r,int x)//字面意思,第一个左端点大于等于x的区间的下标 
{
	int mid;
	while(l<r)
	{
		mid=(l+r)>>1;
		if(A[mid].l<=x)l=mid+1;
		else r=mid;
	}
	if(A[l].l<=x)return l+1;
	return l;
}
ll cross()//通过线段树求出区间的交点对
{
	int i,j,mark=0;
	ll sum=0,first,second;
	for(i=1;i<=n;i++)A[i]=B[i];
	for(i=1;i<=n;i++)if(A[i].l>A[i].r)A[i].r+=360; 
	
	sort(A+1,A+n+1);
	lisanhua();
	S.clear();
	
	for(i=1;i<=n;i++)S.add(1,1,2*n,1,int(A[i].r),1);
	for(i=1;i<n;i++)
	{
		S.add(1,1,2*n,1,int(A[i].r),-1);
		first=S.query(1,1,2*n,int(A[i].r),int(A[i].r));
		second=n-upperbound(i+1,n,A[i].r)+1;
		sum=sum+first-second;
	}
	for(i=1;i<=n;i++)A[i]=B[i];
	for(i=1;i<=n;i++)if(A[i].l>A[i].r)A[i].r+=360; 
	for(i=1;i<=n;i++)if(A[i].r>=360)
	{
		A[i].l-=360;
		A[i].r-=360;
	}
	sort(A+1,A+n+1);
	for(i=1;i<=n;i++)
	{
		if(A[i].l<0)mark++;
		else break;
	}
	lisanhua();
	S.clear();
	for(i=1;i<=n;i++)S.add(1,1,2*n,1,int(A[i].r),1);
	for(i=1;i<=mark&&i<n;i++)
	{
		S.add(1,1,2*n,1,int(A[i].r),-1);
		first=S.query(1,1,2*n,int(A[i].r),int(A[i].r));
		second=n-upperbound(i+1,n,A[i].r)+1;
		sum=sum+first-second;
	}
	S.clear();
	for(i=1;i<=mark;i++)S.add(1,1,2*n,1,int(A[i].r),1);
	for(i=1;i<mark;i++)
	{
		S.add(1,1,2*n,1,int(A[i].r),-1);
		first=S.query(1,1,2*n,int(A[i].r),int(A[i].r));
		second=mark-upperbound(i+1,mark,A[i].r)+1;
		sum=sum-first+second;
	}
	return sum;
}
void work()
{
	ll sum=0;
	sum=cross();
	cout<<sum<<endl;
}
int main()
{
	read();
	work(); 
	return 0;
}