详见 一类算法复合的方法
大概就是把坐标都离散了
按照某x坐标上的点数分类
如果矩形的某边是大类 只有
O(n√)
直接枚举所有点按 y hash就行了
否则所有小类 把所有能构成的线段放进hash表 只有
O(nn√)
再一次体验了unordered_map的感人速度
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<cmath>
#include<tr1/unordered_map>
#include<tr1/unordered_set>
#define pb push_back
using namespace std;
using namespace std::tr1;
typedef vector<int> VI;
typedef long long ll;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
const int N=250005;
int sx[N],icnt;
inline int Bin(int x){
return lower_bound(sx+1,sx+icnt+1,x)-sx;
}
int n;
int x[N],y[N];
VI Y[N];
int cnt[N];
unordered_set<int> Set;
//unordered_map<ll,int> Map;
//typedef unordered_map<ll,int>::iterator IT;
ll AA,AB,BB;
const int M=12500005;
const int P=10000007;
struct HashMap{
ll k[M]; int v[M],next[M];
int head[P],inum;
int&operator[](ll x){
for (int p=head[x%P];p;p=next[p])
if (k[p]==x)
return v[p];
++inum; k[inum]=x; v[inum]=0; next[inum]=head[x%=P]; head[x]=inum;
return v[inum];
}
}Map;
int main(){
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(n);
for (int i=1;i<=n;i++) read(x[i]),read(y[i]);
icnt=0; for (int i=1;i<=n;i++) sx[++icnt]=y[i];
sort(sx+1,sx+icnt+1); icnt=unique(sx+1,sx+icnt+1)-sx-1;
for (int i=1;i<=n;i++) y[i]=Bin(y[i]);
icnt=0; for (int i=1;i<=n;i++) sx[++icnt]=x[i];
sort(sx+1,sx+icnt+1); icnt=unique(sx+1,sx+icnt+1)-sx-1;
for (int i=1;i<=n;i++) x[i]=Bin(x[i]),cnt[x[i]]++,Y[x[i]].pb(y[i]);
for (int i=1;i<=icnt;i++) sort(Y[i].begin(),Y[i].end());
int B=sqrt(n);
for (int i=1;i<=icnt;i++)
if (cnt[i]>B){
for (int j=0;j<cnt[i];j++)
Set.insert(Y[i][j]);
for (int j=1;j<=icnt;j++){
if (i==j) continue;
if (cnt[j]>B){
int c=0;
for (int k=0;k<cnt[j];k++)
if (Set.count(Y[j][k]))
c++;
AA+=(ll)c*(c-1)/2;
}else{
int c=0;
for (int k=0;k<cnt[j];k++)
if (Set.count(Y[j][k]))
c++;
AB+=(ll)c*(c-1)/2;
}
}
Set.clear();
}
for (int i=1;i<=icnt;i++)
if (cnt[i]<=B)
for (int j=0;j<cnt[i];j++)
for (int k=j+1;k<cnt[i];k++)
Map[((ll)Y[i][j]<<32)+Y[i][k]]++;
for (int i=1;i<=Map.inum;i++)
BB+=(ll)Map.v[i]*(Map.v[i]-1)/2;
/*for (IT i=Map.begin();i!=Map.end();i++)
BB+=(ll)i->second*(i->second-1)/2;*/
printf("%lld\n",AA/2+AB+BB);
return 0;
}