Description
给出平面60°角坐标系(也即,以z=(1,0)和w=(0.5, 0.5sqrt(3))为一对基的坐标系)上的N条线段(端点在z,w下的坐标为整数),求图中所有正三角形的面积之和ans。
显然4ans/sqrt(3)是整数。你只需输出这个值对10^9+7的模。
同一片区域属于多个正三角形则计算多次。
input
第一行,一个整数N,为线段数目。
以下N行,每行4个整数a1,b1,a2,b2。表示一条线段从a1z+b1w到a2z+b2w。
保证以下三个命题中恰有一个成立:
1. a1=a2
2. b1=b2
3. a1+b1=a2+b2
这些数值的绝对值不超过10^4。
output
一个整数,代表(4ans/sqrt(3)) mod (10^9+7)。
Sample Input
3
0 0 0 2
0 0 2 0
1 0 0 1
Sample Output
1
Data Constraint
对于30%的数据,N≤233。
对于100%的数据,N≤6666。
保证任意两个线段至多交于一点。
分析
经过在草稿纸上画图,可以发现:平面60°角坐标系上一条线段放在平面直角坐标系上,有三种情况:
1. 与x轴平行
2. 与y轴平行
3. 与坐标轴夹角为45°,可以用x+y+c=0表示
对于一个平面60°角坐标系上的一个正三角形,设它的边长为a,则面积为
3√a24
,如果把它放到平面直角坐标系上,它会是一个等腰直角三角形,面积为
a22
然后题目要求算出答案后乘
43√
,那么就相当于统计这些三角形的
a2
之和
满分算法
把线段放在平面直角坐标系上,先枚举每个与x轴平行的线段,然后找出另外两种线段中所有与它相交的。之后枚举与y轴平行的线段,然后用一个树状数组查询第3种线段中能与它组成等腰直角三角形的,统计答案即可。
设这个交点坐标为(x,y),这个与y轴平行的线段下端点纵坐标为y1,上端点纵坐标为y2。
那么我们要查询的第3种线段,是那些x+y1≤-c≤x+y2的。答案就是
∑(−c−(x+y))2
,把这个式子展开,发现要用树状数组维护三个值。
最后注意插入和删除
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=6675,maxm=40005,mo=1e9+7,N=40001;
typedef long long LL;
int n,ans,s1,s2,a[maxn],b[maxn],c[maxn];
LL t1[maxm],t2[maxm],t3[maxm];
struct edge
{
int typ,x1,y1,x2,y2;
}A[maxn];
bool cmp(int x,int y)
{
return !A[y].typ && A[x].x1<=A[y].x1 && A[y].x1<=A[x].x2 && A[y].y1<=A[x].y1 && A[x].y1<=A[y].y2 ||
A[y].typ==2 && A[x].x1+A[x].y1<=A[y].x1+A[y].y1 && A[x].x2+A[x].y2>=A[y].x1+A[y].y1 && A[y].y2<=A[x].y1 && A[y].y1>=A[x].y1;
}
bool cmp1(int x,int y)
{
return A[x].x1<A[y].x1;
}
bool cmp2(int x,int y)
{
return A[x].x2<A[y].x2;
}
int lowbit(int x)
{
return x & (-x);
}
void add(LL x,int y)
{
for (int i=x+20001;i<=N;i+=lowbit(i))
{
t1[i]=(t1[i]+mo+x*y) % mo; t2[i]=(t2[i]+mo+x*x % mo * y) % mo; t3[i]+=y;
}
}
int sum(int x,int y)
{
LL a=0,b=0,c=0;
for (y+=20001;y;y-=lowbit(y))
{
a=(a+t2[y]) % mo; b=(b+t1[y]) % mo; c+=t3[y];
}
return (a+mo-2 * b % mo * x % mo + c * x % mo * x) % mo;
}
int main()
{
scanf("%d",&n);
for (int i=0;i<n;i++)
{
scanf("%d%d%d%d",&A[i].x1,&A[i].y1,&A[i].x2,&A[i].y2);
if (A[i].y1==A[i].y2)
{
A[i].typ=1;
if (A[i].x1>A[i].x2) A[i].x1^=A[i].x2^=A[i].x1^=A[i].x2;
}else if (A[i].x1!=A[i].x2)
{
A[i].typ=2;
if (A[i].x1>A[i].x2)
{
A[i].x1^=A[i].x2^=A[i].x1^=A[i].x2;
A[i].y1^=A[i].y2^=A[i].y1^=A[i].y2;
}
}else if (A[i].y1>A[i].y2) A[i].y1^=A[i].y2^=A[i].y1^=A[i].y2;
}
for (int i=0;i<n;i++) if (A[i].typ==1)
{
s1=s2=0;
for (int j=0;j<n;j++) if (cmp(i,j))
{
if (A[j].typ==2) a[s1++]=j;else c[s2++]=j;
}
memcpy(b,a,s1*4);
sort(a,a+s1,cmp1);
sort(b,b+s1,cmp2);
sort(c,c+s2,cmp1);
memset(t1,0,sizeof(t1));
memset(t2,0,sizeof(t2));
memset(t3,0,sizeof(t3));
int h=0,t=0,y=A[i].y1;
for (int j=0;j<s2;j++)
{
for (;h<s1 && A[a[h]].x1<=A[c[j]].x1;h++) add(A[a[h]].x1+A[a[h]].y1,1);
for (;t<s1 && A[b[t]].x2<A[c[j]].x1;t++) add(A[b[t]].x1+A[b[t]].y1,-1);
ans=((ans+sum(y+A[c[j]].x1,A[c[j]].x1+A[c[j]].y2)) % mo + mo - sum(y+A[c[j]].x1,A[c[j]].x1+A[c[j]].y1-1)) % mo;
}
}
printf("%d\n",ans);
return 0;
}