设抛物线为
y=ax2+by
那么一个限制
y1<=ax2+by<=y2
转化为
b<=−ax+y2xb>=−ax+y1x
然后就是一个关于a b的半平面交
这个直接上模板就行了 据说加强的数据是一些半平面交是点 直线 线段 射线 之类的边界情况
我long double卡精度卡到1e-14就过了
还有一个问题就是这个抛物线应该满足 a<0 才符合生活实际 不知道数据有没有考虑到
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<vector>
#include<cstring>
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
typedef long double ld;
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(ld &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;
}
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;
}
inline int sgn(ld a){
if (fabs(a)<1e-14) return 0; if (a<0) return -1; return 1;
}
const int N=200005;
const ld PI=acos(-1.0);
struct P{
ld x,y;
void read() { double _x,_y; scanf("%lf%lf",&_x,&_y); x=_x; y=_y; }
P(ld x=0,ld y=0):x(x),y(y) { }
P rot(ld A){ return P(x*cos(A)-y*sin(A),x*sin(A)+y*cos(A)); }
ld dist(){ return sqrt(x*x+y*y); }
friend P operator + (P A,P B) { return P(A.x+B.x,A.y+B.y); }
friend P operator - (P A,P B) { return P(A.x-B.x,A.y-B.y); }
friend ld operator * (P A,P B) { return A.x*B.y-B.x*A.y; }
friend P operator * (P A,ld B) { return P(A.x*B,A.y*B); }
friend P operator / (P A,ld B) { return P(A.x/B,A.y/B); }
friend ld dist(P A,P B){ return (A-B).dist(); }
}p[N];
struct Tl{
P p1,p2; int idx; ld ang;
Tl() { }
Tl(P _p1,P _p2,int id) { p1=_p1; p2=_p2; idx=id; ang=atan2(p2.y-p1.y,p2.x-p1.x); }
friend bool operator < (const Tl &A,const Tl &B){
return sgn(A.ang-B.ang)==0?sgn((A.p1-B.p1)*(B.p2-B.p1))<0:sgn(A.ang-B.ang)<0;
}
friend P cross(const Tl &A,const Tl &B){
ld ta=(A.p2-B.p1)*(A.p1-B.p1),tb=(A.p1-B.p2)*(A.p2-B.p2);
return B.p1*(tb/(ta+tb))+B.p2*(ta/(ta+tb));
}
}L[N],line[N]; int tot,Tot;
inline bool onleft(Tl& l1,Tl &l2,Tl &l3){
P tp=cross(l1,l2);
return sgn((tp-l3.p1)*(l3.p2-l3.p1))<=0;
}
int Q[N],l,r;
inline bool hpi(){
l=1,r=0; Q[++r]=1;
for (int i=2;i<=tot;i++){
while (l<r && !onleft(L[Q[r-1]],L[Q[r]],L[i]))
r--;
while (l<r && !onleft(L[Q[l+1]],L[Q[l]],L[i]))
l++;
Q[++r]=i;
}
while (l<r && !onleft(L[Q[r-1]],L[Q[r]],L[Q[l]])) r--;
while (l<r && !onleft(L[Q[l+1]],L[Q[l]],L[Q[r]])) l++;
return r-l>=2;
}
int n;
#define calc(a,b,x) ((b)/(a)-(a)*(x))
inline bool check(int mid){
tot=0; L[tot].ang=1e20;
for (int i=1;i<=Tot;i++)
if (line[i].idx<=mid)
if (sgn(line[i].ang-L[tot].ang))
L[++tot]=line[i];
return hpi();
}
#define oo 1e15
int main(){
ld x,y1,y2;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(n);
line[++Tot]=Tl(P(-oo,-oo),P(oo,-oo),0);
line[++Tot]=Tl(P(oo,-oo),P(oo,oo),0);
line[++Tot]=Tl(P(oo,oo),P(-oo,oo),0);
line[++Tot]=Tl(P(-oo,oo),P(-oo,-oo),0);
for(int i=1;i<=n;i++){
read(x); read(y1); read(y2);
line[++Tot]=Tl(P(-1,calc(x,y1,-1)),P(1,calc(x,y1,1)),i);
line[++Tot]=Tl(P(1,calc(x,y2,1)),P(-1,calc(x,y2,-1)),i);
}
sort(line+1,line+Tot+1);
int L=0,R=n+1,MID;
while (L+1<R)
if (check(MID=(L+R)>>1))
L=MID;
else
R=MID;
printf("%d\n",L);
return 0;
}
然后因为这里就只是要求判断交是否为空 我们可以上随机增量法
期望复杂度是
O(n)
的 证明同其他应用随机增量法的题
上一张图 来自 随机增量算法 解轶伦
这次我卡精度卡到1e-19?
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<vector>
#include<cstring>
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
typedef long double ld;
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;
}
inline int sgn(ld a){
if (fabs(a)<1e-19) return 0; if (a<0) return -1; return 1;
}
const int N=200005;
const ld PI=acos(-1.0);
struct P{
ld x,y;
P(ld x=0,ld y=0):x(x),y(y) { }
}p[N];
struct Tl{
ld k,b; int dir; // 0 : <= ; 1 : >=
Tl(ld k=0,ld b=0,int dir=0):k(k),b(b),dir(dir) { }
P calc(ld x){ return P(x,k*x+b); }
bool jud(P p){
if (dir==0) return sgn(p.y-k*p.x-b)<=0;
else return sgn(p.y-k*p.x-b)>=0;
}
friend ld crossx(Tl A,Tl B){ return (B.b-A.b)/(A.k-B.k); }
friend P cross(Tl A,Tl B){ return A.calc(crossx(A,B)); }
}L[N]; int tot;
int n,xs[N],ys1[N],ys2[N];
int main(){
ld x,y1,y2;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(n);
for (int i=1;i<=n;i++) read(xs[i]),read(ys1[i]),read(ys2[i]);
tot=0;
for (int i=1;i<=n;i++){
L[++tot]=Tl(-xs[i],(double)ys1[i]/xs[i],1);
L[++tot]=Tl(-xs[i],(double)ys2[i]/xs[i],0);
}
P p=L[1].calc(1);
for (int i=2;i<=tot;i++)
if (!L[i].jud(p)){
ld l=-1e15,r=1e15,t;
for (int j=1;j<i;j++){
if (sgn(L[i].k-L[j].k)==0) continue;
t=crossx(L[j],L[i]);
if (L[j].jud(L[i].calc(t+1))) l=max(l,t);
if (L[j].jud(L[i].calc(t-1))) r=min(r,t);
}
if (sgn(l-r)>0) {
printf("%d\n",(i+1)/2-1);
return 0;
}
if (l>-1e15 && r<1e15)
p=L[i].calc((l+r)/2);
else if (l>-1e15)
p=L[i].calc(l);
else
p=L[i].calc(r);
}
printf("%d\n",n);
return 0;
}