链接
题解
出题人用的树状数组,我这里开了个平衡树维护偏序,其实一样
代码
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define iinf 0x3f3f3f3f
#define linf (1ll<<60)
#define eps 1e-8
#define maxn 1000010
#define maxe 1000010
#define cl(x) memset(x,0,sizeof(x))
#define rep(i,a,b) for(i=a;i<=b;i++)
#define drep(i,a,b) for(i=a;i>=b;i--)
#define em(x) emplace(x)
#define emb(x) emplace_back(x)
#define emf(x) emplace_front(x)
#define fi first
#define se second
#define de(x) cerr<<#x<<" = "<<x<<endl
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<double,double> pdd;
const double pi = acos(-1);
ll read(ll x=0)
{
ll c, f(1);
for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
for(;isdigit(c);c=getchar())x=x*10+c-0x30;
return f*x;
}
#define sqr(x) ((x)*(x))
int sign(double x)
{
if(x<-eps)return -1;
if(x>eps)return 1;
return 0;
}
struct point
{
double x, y;
point(double x, double y):x(x),y(y){}
point(){}
}_;
struct vec
{
point o; double x, y;
vec(point o, double x, double y):o(o),x(x),y(y){}
vec(){};
vec operator+(vec v){return vec(_, x+v.x, y+v.y);} //向量和
vec operator-(vec v){return vec(_, x-v.x, y-v.y);} //向量差
double operator^(vec v){return x*v.y - v.x*y;} //向量内积
double operator*(vec v){return x*v.x + y*v.y;} //向量外积
vec operator*(double t){return vec(_, x*t, y*t);} //向量数乘
double abs2(){return sqr(x)+sqr(y);} //模的平方
double abs(){return sqrt(abs2());} //模
vec rot(double th) //逆时针旋转,精度很差
{return vec(o, -sin(th)*y+cos(th)*x, cos(th)*y+sin(th)*x );}
vec rot(double sinth, double costh) //逆时针旋转,精度取决于sinth和costh
{return vec(o, -sinth*y+costh*x, costh*y+sinth*x );}
vec trunc(double l){return (*this)*(l/abs());} //把向量v的长度改为l,方向不变
};
point operator+(point p, vec v){return point(p.x+v.x, p.y+v.y);} //点沿着向量方向平移
vec operator-(point p1, point p2){return vec(p2,p1.x-p2.x,p1.y-p2.y);}//用两点构造向量
bool on(point p, vec v){return sign((p-v.o)^v)==0;} //点在直线上
point projection(point p, vec v){return v.o + v*((p-v.o)*v/v.abs2());} //求投影点
int n;
point a, b, pt[maxn];
int main()
{
int i;
n = read();
a.x=read(), a.y=read();
b.x=read(), b.y=read();
vec ab = b-a;
double sinth = ab.y/ab.abs(), costh = ab.x/ab.abs();
vector<pdd> v1, v2;
rep(i,1,n)
{
double x(read()), y(read());
auto v = ( point(x,y) - a ).rot(-sinth,costh);
auto th1 = fabs(atan2(v.y,v.x)), th2 = pi-fabs(atan2(v.y,v.x-ab.abs()));
if(sign(v.y)>0)v1.emb( make_pair(th1,th2) );
else v2.emb( make_pair(th1,th2) );
}
ll ans(0);
tree<pdd,null_type,less<pdd>,rb_tree_tag,tree_order_statistics_node_update> tr;
tr.clear();
sort(v1.begin(),v1.end());
for(auto pr:v1)
{
auto ord = tr.order_of_key(pdd(pr.se,pr.fi));
ans += ord;
tr.insert(pdd(pr.se,pr.fi));
}
tr.clear();
sort(v2.begin(),v2.end());
for(auto pr:v2)
{
auto ord = tr.order_of_key(pdd(pr.se,pr.fi));
ans += ord;
tr.insert(pdd(pr.se,pr.fi));
}
tr.clear();
sort(v1.begin(),v1.end(),greater<pdd>());
sort(v2.begin(),v2.end());
auto it = v2.begin();
for(auto pr:v1)
{
while(it!=v2.end() and it->fi < pi - pr.fi )tr.insert( pdd(it->se,it->fi) ), it++;
auto ord = tr.order_of_key( pdd(pi-pr.se,pr.fi) );
ans += ord;
}
printf("%lld",ans);
return 0;
}