cf#345-C - Watchmen-map离散化

http://codeforces.com/contest/651/problem/C


给你n个点,要求有多少对点满足   |xi - xj| + |yi - yj|.=.

也就是 这两个点 在平行于x或y轴的直线上


x,y的范围太大 1e9,但是n只有2e5

我们把点离散化后,看遍历所有与X轴平行的直线(当然就是只看出现过的x值),看上面有多少个点,如果有X个点,显然 X方向的这些点对答案的贡献就是 (x-1)*x/2

y轴同理


要注意的是,会有重合的点,重合的点 在X或Y方向 的贡献会被计算了两次


只需要把所有点排个序,找出重合点的个数,对于重合的A点X个,只需要减去一次贡献即可,也就是x*(x-1)/2


#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;

const double pi=acos(-1.0);
double eps=0.000001;
  
map<__int64 ,__int64 > ::iterator it;
map<__int64 ,__int64 > sbx,sby;
struct node
{
	__int64 x,y;
};
bool cmp(node a,node b)
{
	if (a.x!=b.x)
	return a.x<b.x;
	return a.y<b.y;
}
node tm[200005];
int main()
{
	
	  int n;
	  cin>>n;
	  __int64 i;
	  for (i=1;i<=n;i++)
	  {
		  scanf("%I64d%I64d",&tm[i].x,&tm[i].y);
		  sbx[tm[i].x]++;
		  sby[tm[i].y]++;
	  }
	  sort(tm+1,tm+1+n,cmp);
	 
	
	  __int64 ans=0;
	for (it=sbx.begin();it!=sbx.end();it++)
	{
		__int64 tmp=it->second;
		ans+=tmp*(tmp-1)/2;
	}
	for (it=sby.begin();it!=sby.end();it++)
	{
		__int64 tmp=it->second;
		ans+=tmp*(tmp-1)/2;
	}
	__int64 ret=0;
	    for (i=1;i<=n;i++)
	  {
		  int j=i+1;
		 while (tm[i].x==tm[j].x&&tm[i].y==tm[j].y&&j<=n)
			  j++;
		  ret=j-i;
		 ans-=ret*(ret-1)/2;
		 i=j-1;
	  }
	printf("%I64d\n",ans);
	
	
	
	
	
	
	return 0;
	
}


你可能感兴趣的:(cf#345-C - Watchmen-map离散化)