[阈值] SPOJ RECTANGL - Rectangles

详见 一类算法复合的方法

大概就是把坐标都离散了
按照某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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值