题解-富有物理组的风采

Problem

链接

简要题意:给定平面上\(n\)个点,求有多少种选取四个点的方案使得这四个点所构成的四边形为与坐标轴平行的矩形

\(n,x,y\leq 10^5\)

Solution

相信dalao的你一定能在一个极短的时间\(\Delta T\)内想到这道水题的做法

我们首先考虑暴力做法,首先找到一个平行于坐标轴的矩形可以枚举横坐标或者纵坐标,则有一个骗分策略就是如果不同的横坐标比较少,我们枚举横坐标,如果不同的纵坐标比较少,我们枚举纵坐标

细化一下做法,如果枚举横坐标,对于每一对横坐标\(x_1,x_2\),如果在相同的纵坐标处有都有点(即\((x_1,y),(x_2,y)\)都有点),我们将计数器\(cnt\)加一,最后这对横坐标的贡献就是\(\binom {cnt}2\)

如果枚举纵坐标,稍微转化一下,在枚举横坐标时进行统计,相应的,如果对于一个横坐标\(x\),在\((x,y_1),(x,y_2)\)处都有点,则对于数对\((y_1,y_2)\)进行计数,最后如果数对\((y_1,y_2)\)出现了\(cnt\)次,则对于答案的贡献为\(\binom {cnt}2\)

想到这就有眉目了,当然是套路分块啦

我们先设置一个参数\(L\),然后枚举出现过的横坐标\(x\),如果在这个横坐标上出现的点的个数超过\(L\),使用第一个做法,如果不足\(L\),使用第二个做法

现在来分析复杂度:对于第一个算法,调用不会超过\(\frac NL\)次,每次实现复杂度\(O(N)\),总复杂度\(O(\frac {N^2}L)\);对于第二个算法,调用不超过\(N\)次,每次实现复杂度不超过\(O(L)\),总复杂度为\(O(NL)\)

所以整个算法的复杂度为\(O(\frac {N^2}L+NL)\),运用不等式思想很快发现当\(L\)\(\sqrt N\)时最快,整体复杂度为\(O(N\sqrt N)\)

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rg register

template <typename _Tp> inline _Tp read(_Tp&x){
	char c11=getchar(),ob=0;x=0;
	while(c11^'-'&&!isdigit(c11))c11=getchar();if(c11=='-')ob=1,c11=getchar();
	while(isdigit(c11))x=x*10+c11-'0',c11=getchar();if(ob)x=-x;return x;
}

const int N=101000,L=300;
struct Edge{int v,nxt;}a[N*80];
int X[N],Y[N],stx[N],cX[N],t[N];
int n,m,_;ll ans;

inline void add(int*arr,int u,int v){a[++_].v=v,a[_].nxt=arr[u],arr[u]=_;}

void init();
void work();
int main(){
	init();
	work();
	return 0;
}

void work(){
	int nn=unique(stx+1,stx+n+1)-stx-1;
	for(rg int id=1;id<=nn;++id)
		if(cX[stx[id]]>=L){
			for(rg int i=X[stx[id]];i;i=a[i].nxt)
				t[a[i].v]=1;
			for(rg int i=1;i<=nn;++i)
				if(i<id||cX[stx[i]]<L){
					int res(0);
					for(rg int j=X[stx[i]];j;j=a[j].nxt)
						res+=t[a[j].v];
					ans+=1ll*res*(res-1)>>1;
				}
			for(rg int i=X[stx[id]];i;i=a[i].nxt)
				t[a[i].v]=0;
		}else {
			for(rg int i=X[stx[id]];i;i=a[i].nxt)
			for(rg int j=a[i].nxt;j;j=a[j].nxt)
				if(a[i].v<a[j].v)add(Y,a[i].v,a[j].v);
				else add(Y,a[j].v,a[i].v);
		}
	for(rg int i=1;i<N;++i)if(Y[i]){
		for(rg int j=Y[i];j;j=a[j].nxt)
			ans+=(t[a[j].v]++);
		for(rg int j=Y[i];j;j=a[j].nxt)
			--t[a[j].v];
	}printf("%lld\n",ans);
}

void init(){
	read(n);
	for(rg int i=1,yy;i<=n;++i){
		++cX[read(stx[i])];
		read(yy);add(X,stx[i],yy);
	}sort(stx+1,stx+n+1);
}
posted @ 2018-09-25 20:40  oier_hzy  阅读(149)  评论(0编辑  收藏  举报