Description
圆上有 2 ∗ n 个点和连接这些点的 n 条弦,这些弦不会在圆上相交。这2 ∗ n 个点按照在圆上的位置顺序依次标号为 1,2,...,2 ∗ n。
请求出有多少个无序的三元组,使得对应的三条弦可以通过距离的缩放中心对称。
Input
第一行一个数 n (n ≤ 100000)。
接下来 n 行,每行两个数,表示该弦的端点。保证一个数不会出现两次。
Output
输出一个数,表示方案数。
Sample Input
样例输入1: 4 5 4 1 2 6 7 8 3 样例输入2: 8 1 7 2 4 3 9 5 11 6 8 10 16 13 15 14 12
Sample Output
样例输出1:2 样例输出2:6
Data Constraint
对于30%数据,n ≤ 100.
对于60%数据,n ≤ 10000.
对于100%数据,n ≤ 100000.
Hint
1. 什么是距离缩放?
无视圆上的点之间的绝对距离,只考虑其相对顺序。
2. 何谓中心对称?
旋转 2π /3 后与原图形相同。
Solution
题目大意实际上就是给你圆上的n条弦,让你求出三条弦不相交或两两相交的方案数。
我们要算的,是2和5的答案,但是直接算不好算。
所以算1,3,4的,减去他们的就好了。
我们将圆从一个点(1号点)断开变成一条线段,并且将每条弦看成从较小编号的点到编号大的点的一条弦(不管它所对的弧是优弧还是劣弧)。
那么就变成了如图所示。情况一可以视作由图中(蓝色3、红色、蓝色4)所构成的一种方案,而情况二可以视作(蓝色1、蓝色4、蓝色2)构成的方案。
那么对于每条线段,我们分别求出它的x[i],y[i],z[i]=n-1-x[i]-y[i]。
那么对应的情况一的方案为x[i]*y[i],情况三、四的总和为z[i]*(x[i]+y[i]),最后我们要将情况三四的总和除以2,因为在相交的两条弦的每一条中我们都计算了一次答案,接下来讲讲怎么求x[i]和y[i]。
x[i]=蓝色线段1、2、3的总和(即能够包含当前线段的线段个数)。
y[i]=蓝色线段4的总和(即包含在当前线段中的线段个数)。
分开求,可以将线段左右端点拆开,从小到大加入。
对于线段1,我们可以在处理到当前线段左端点时统计前面的右端点的个数。
对于线段2,处理到右端点时统计后面的左端点的个数。
但是如果我们的左端点按顺序加入就统计不到线段2,所以我们先将所以的左端点加入树状数组中,这样不影响。
对于线段3,我们可以在遇到每个左端点时将右端点加入第二个树状数组中,那么它就是当前(在左端点以前)加入树状数组中的右端点在这条线段右端点右边的个数。
对于线段4,可以在到这条线段左端点时统计一次这条线段内部的右端点的个数,到这条线段右端点时再统计一次,两次作差就可以得到内部的线段的个数。
最后答案为.。
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define I int
#define ll long long
#define A(op) a[i].op
#define F(i,a,b) for(register int i=a;i<=b;++i)
#define N 100004
using namespace std;
I n,m,k,l,r,t,c[2][N<<1],b[N<<1];
ll ans,x[N],y[N];
struct node{I x,d;}a[N<<1];
I cmp(node x,node y){return x.x<y.x;}
void add(I x,I y){for(;x<=t;x+=x&-x) c[y][x]++;}
ll ask(I x,I y){ll st=0;for(;x;x-=x&-x) st+=c[y][x];return st;}
I main(){
freopen("Magic.in","r",stdin);
freopen("Magic.out","w",stdout);
scanf("%d",&n);
F(i,1,n){
scanf("%d%d",&l,&r);if(l>r) swap(l,r);
a[++t]=node{l,i},a[++t]=node{r,i+n};
}
sort(a+1,a+1+n*2,cmp);
F(i,1,t){
b[A(d)]=i;
if(A(d)<=n) add(A(x),0);
}
F(i,1,t){
k=A(d)-(A(d)>n)*n;
if(A(d)>n){
x[k]=x[k]-ask(A(x),0);
y[k]=ask(A(x)-1,1)-ask(a[b[k]].x,1)-y[k];
}
else{
add(a[b[k+n]].x,1);
x[k]+=ask(A(x),1)+ask(t,0)+ask(n*2,1)-ask(a[b[k+n]].x,1);
y[k]=ask(a[b[k+n]].x-1,1)-ask(A(x),1);
}
}
ans=(ll)n*(n-1)*(n-2)/6;
F(i,1,n) ans=ans-x[i]*y[i]-(x[i]+y[i])*(n-1-x[i]-y[i])/2;
printf("%lld\n",ans);
return 0;
}