题解:P2950 [USACO09OPEN] Bovine Embroidery G
Drink_Assam · · 题解
我是 50 号,喜欢 29 号,所以一定要做 P2950。
题意:给定一个以原点为圆心且半径为
分析两条直线相交于圆内或圆上的条件。考虑取它们和圆的四个交点,如图(图片来源 @fy0123)。\ \ 可以发现,当且仅当交点交叉排列,直线交于圆内或圆上(若交于圆上,则交点重合,也可以通过交换重合点构造出交叉排列)。
断环成链,不妨将点转化为它与原点连线的倾斜角,直线转化为倾斜角的闭区间,相交于圆内或圆上当且仅当:两个区间不真包含且有交。
然后就做完了,变成了二维偏序。具体地,将区间按左端点排序,从左到右将右端点放入树状数组,查询区间内包含多少个右端点即可。
AC 代码。
#include <bits/stdc++.h>
#define fi first
#define se second
#define mid ((l+r)>>1)
#define bmid ((l+r+1)>>1)
#define pb push_back
#define eb emplace_back
using namespace std;
using ll= long long;
#ifndef ONLINE_JUDGE
template <typename tp>
void _debug(const tp& t) {cerr<<t<<'\n';}
template <typename tp,typename... args>
void _debug(const tp& t, const args&... rest) {cerr<<t<<' ';_debug(rest...);}
#define debug(...) _debug(#__VA_ARGS__ " =", __VA_ARGS__)
#else
#define debug(...) 0
#endif
#define int ll
#define eps 1e-9
const int N=100005,H=N<<2,inf=1000000000,mod=1000000007;
int n,d;
pair<double,double> hht(int a,int b,double c) {
if(a<0) a*=-1,b*=-1,c*=-1;
int dlt=b*b-4*a*c;
if(dlt<0) return make_pair(1,0);
return make_pair((-b-sqrt(dlt))/(a<<1),(-b+sqrt(dlt))/(a<<1));
}
pair<double,double> llq(int a,int b,double c){
double x1,y1,x2,y2;
if(!a) {
y1=y2=-c/b;
if(y1<-d-eps||y1>d+eps) return make_pair(1,0);
x1=sqrt(d*d-y1*y1);
x2=-x1;
} else {
auto t=hht(a*a+b*b,2*b*c,c*c-double(a*a)*d*d);
y1=t.fi,y2=t.se;
if(y1>y2) return make_pair(1,0);
x1=-(b*y1+c)/a,x2=-(b*y2+c)/a;
}
double ret1=atan2(x1,y1),ret2=atan2(x2,y2);
if(ret1<ret2-eps) return make_pair(ret1,ret2);
else return make_pair(ret2,ret1);
}
vector<pair<double,int> > vec;
int V,c[N];
void add(int i,int x) {
for(;i<=V;i+=i&-i)
c[i]+=x;
}
int query(int i) {
int ret=0;
for(;i;i-=i&-i)
ret+=c[i];
return ret;
}
signed main() {
cin.tie(nullptr)->sync_with_stdio(false);
cin>>n>>d;
for(int a,b,c,i=1;i<=n;i++) {
cin>>a>>b>>c;
if(abs(c)>d*sqrt(a*a+b*b)) {n--,i--;continue;}
auto t=llq(a,b,c);
vec.eb(t.fi,i),vec.eb(t.se,i);
}
sort(vec.begin(),vec.end());
vector<vector<int> > ran(n+1);
for(int p=0;p<vec.size();) {
V++;
do ran[vec[p++].se].pb(V);
while(p<vec.size()&&fabs(vec[p].fi-vec[p-1].fi)<eps);
}
for(int i=1;i<=n;i++) {
sort(ran[i].begin(),ran[i].end());
}
sort(ran.begin()+1,ran.begin()+n+1,[](auto x,auto y) {
return x[0]!=y[0]?x[0]<y[0]:x[1]<y[1];
});
int ans=0;
for(int i=1;i<=n;i++) {
debug(ran[i][0],ran[i][1]);
ans+=query(ran[i][1])-query(ran[i][0]-1);
add(ran[i][1],+1);
}
cout<<ans;
return 0;
}