ferinの競プロ帳

競プロについてのメモ

CSA Round #68 C Right Triangles

問題ページ
CS Academy

概要

2次元座標上のN点(x, y)が与えられる。各点について3点(x,y)(0,0)(x,0)を結んでできる三角形の内部に他のN-1点のうち何個が含まれているか求めろ

2 <= N <= 10^5
1 <= x,y <= 10^5
xは全て異なる
原点と(x,y)を結んだ線上に他の点は存在しない

考えたこと

  • xが小さい順に点を並べておくとその点より前に出たy座標がより小さい点は三角形の内部に入ってる気持ちになる
  • BITで数えればいい気持ちになる
  • 冷静になって考えると嘘(サンプルが弱すぎる)
  • どんな状況で点が三角形の内部に入るのか
  • (x1, y1)がつくる三角形の中に(x2, y2)が入るときはx2 < x1, y1/x1 > y2/x2 になる
  • 傾きでソートして前に出たx座標がより小さい点の数を数えるとよさそう
  • BITでできるのでO(NlogN)
#include <bits/stdc++.h>

using namespace std;
using ll = long long;
#define int ll
using VI = vector<int>;
using PII = pair<int, int>;

#define FOR(i, a, n) for (ll i = (ll)a; i < (ll)n; ++i)
#define REP(i, n) FOR(i, 0, n)
#define ALL(x) x.begin(), x.end()
#define PB push_back

const ll LLINF = (1LL<<60);
const int INF = (1LL<<30);
const int MOD = 1000000007;

template <typename T> T &chmin(T &a, const T &b) { return a = min(a, b); }
template <typename T> T &chmax(T &a, const T &b) { return a = max(a, b); }
template <typename T> bool IN(T a, T b, T x) { return a<=x&&x<b; }
template<typename T> T ceil(T a, T b) { return a/b + !!(a%b); }
template<class S,class T>
ostream &operator <<(ostream& out,const pair<S,T>& a){
  out<<'('<<a.first<<','<<a.second<<')';
  return out;
}
template<class T>
ostream &operator <<(ostream& out,const vector<T>& a){
  out<<'[';
  REP(i, a.size()) {out<<a[i];if(i!=a.size()-1)out<<',';}
  out<<']';
  return out;
}

int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0};

int bit[100010], m = 100010;

//0からi-1番目までの和
int sum(int i) {
  i++;
  int s = 0;
  while(i > 0) {
    s += bit[i];
    i -= i&-i;
  }
  return s;
}

//i番目(0-index)にxを加える
void add(int i, int x) {
  i++;
  while(i <= m) {
    bit[i] += x;
    i += i&-i;
  }
}

int dp[100010], x[100010], y[100010];
signed main(void)
{
  int n;
  cin >> n;
  vector<pair<double, int>> v;
  REP(i, n) {
    cin >> x[i] >> y[i];
    v.PB({(double)y[i]/x[i], i});
  }
  sort(ALL(v));

  dp[v[0].second] = 0;
  add(x[v[0].second], 1);
  FOR(i, 1, n) {
    dp[v[i].second] = sum(x[v[i].second]);
    add(x[v[i].second], 1);
  }

  REP(i, n) {
    cout << dp[i] << endl;
  }

  return 0;
}