BZOJ2646 : neerc2011 flight

答案由$3$部分构成:

$1$.抛物线的极值。

$2$.询问区间的左端点在抛物线上的值。

$3$.询问区间的右端点在抛物线上的值。

对于$1$,就是某个矩形范围内最大值查询,使用KD-Tree可以在$O(\sqrt{n})$的时间内完成询问。

对于$2$和$3$,对编号建线段树,每个节点维护该区间内最上方的轮廓线,那么每个节点的轮廓线可以由左右儿子的轮廓线通过归并得到。

归并时不断对两条抛物线求交点,在相邻关键点之间取较高的一段。

为了减小常数,可以在归并完成后将连续的所属同一条抛物线的轮廓线连起来。

查询时在线段树上找到$O(\log n)$个节点,然后在那些节点的轮廓线上二分查找即可。

总时间复杂度$O(n\log n+m(\log^2n+\sqrt{n}))$。

 

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<vector>
#define PB push_back
using namespace std;
const int N=50010;
const double eps=1e-6;
namespace KD{
int root,cmp_d,ans,X1,X2,Y1,Y2;
struct node{int d[2],l,r,Max[2],Min[2],val,sum;}t[N];
inline bool cmp(const node&a,const node&b){return a.d[cmp_d]<b.d[cmp_d];}
inline void umax(int&a,int b){if(a<b)a=b;}
inline void umin(int&a,int b){if(a>b)a=b;}
inline void up(int x){
  if(t[x].l){
    umax(t[x].Max[0],t[t[x].l].Max[0]);
    umin(t[x].Min[0],t[t[x].l].Min[0]);
    umax(t[x].Max[1],t[t[x].l].Max[1]);
    umin(t[x].Min[1],t[t[x].l].Min[1]);
    umax(t[x].sum,t[t[x].l].sum);
  }
  if(t[x].r){
    umax(t[x].Max[0],t[t[x].r].Max[0]);
    umin(t[x].Min[0],t[t[x].r].Min[0]);
    umax(t[x].Max[1],t[t[x].r].Max[1]);
    umin(t[x].Min[1],t[t[x].r].Min[1]);
    umax(t[x].sum,t[t[x].r].sum);
  }
}
int build(int l,int r,int D){
  int mid=(l+r)>>1;
  cmp_d=D;
  nth_element(t+l+1,t+mid+1,t+r+1,cmp);
  t[mid].Max[0]=t[mid].Min[0]=t[mid].d[0];
  t[mid].Max[1]=t[mid].Min[1]=t[mid].d[1];
  t[mid].sum=t[mid].val;
  if(l!=mid)t[mid].l=build(l,mid-1,!D);
  if(r!=mid)t[mid].r=build(mid+1,r,!D);
  return up(mid),mid;
}
void ask(int x){
  if(t[x].Min[0]>X2||t[x].Max[0]<X1||t[x].Min[1]>Y2||t[x].Max[1]<Y1||t[x].sum<=ans)return;
  if(t[x].Min[0]>=X1&&t[x].Max[0]<=X2&&t[x].Min[1]>=Y1&&t[x].Max[1]<=Y2){
    ans=t[x].sum;
    return;
  }
  if(t[x].d[0]>=X1&&t[x].d[0]<=X2&&t[x].d[1]>=Y1&&t[x].d[1]<=Y2)umax(ans,t[x].val);
  if(t[x].l)ask(t[x].l);
  if(t[x].r)ask(t[x].r);
}
inline int query(int A,int B,int C,int D){
  ans=0;
  X1=A,X2=B,Y1=C,Y2=D;
  ask(root);
  return ans;
}
inline void init(int i,int x,int y){t[i].d[0]=i,t[i].d[1]=x,t[i].val=y;}
}
inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
int n,m,i,A,B,C,D,a[N][3];double ans;
struct E{
  double a,b,c;long long X,Y;
  E(){}
  E(double p,double x,double y,int _X,int _Y){
    a=-y/(p-x)/(p-x);
    b=-2*a*x;
    c=y+a*x*x;
    X=1LL*_X*_X,Y=_Y;
  }
  inline double f(double x){return a*x*x+b*x+c;}
}e[N];
inline double pos(const E&a,const E&b,double l,double r){
  double A=a.a-b.a,B=a.b-b.b,C=a.c-b.c;
  if(a.X*b.Y==a.Y*b.X){
    if(fabs(B)<eps)return r;
    double x=-C/B;
    if(x>l+eps&&x<r)return x;
    return r;
  }
  double d=B*B-4*A*C;
  if(d<-eps)return r;
  d=sqrt(d);
  double x=(-B-d)/(2*A),y=(-B+d)/(2*A),ret=r;
  if(x>l+eps&&x<r)ret=x;
  if(y>l+eps&&y<r)ret=min(ret,y);
  return ret;
}
struct P{
  double l,r;int p;
  P(){}
  P(double _l,double _r,int _p){l=_l,r=_r,p=_p;}
};
vector<P>v[131100],c;
vector<double>q;
inline void merge(vector<P>&f,const vector<P>&a,const vector<P>&b){
  int na=a.size(),nb=b.size(),i=0,j=0,k,top=0;
  c.clear();
  q.clear();
  q.PB(-N);
  while(i<na&&j<nb)if(a[i].r<b[j].r||j==nb){
    if(a[i].r>q[top]+eps)q.PB(a[i].r),top++;
    i++;
  }else{
    if(b[j].r>q[top]+eps)q.PB(b[j].r),top++;
    j++;
  }
  for(;i<na;i++)if(a[i].r>q[top]+eps)q.PB(a[i].r),top++;
  for(;j<nb;j++)if(b[j].r>q[top]+eps)q.PB(b[j].r),top++;
  for(i=j=k=0;k<top;k++){
    double l=q[k],r=q[k+1];
    while(i<na&&a[i].r+eps<r)i++;
    while(j<nb&&b[j].r+eps<r)j++;
    if(i==na||a[i].l>l+eps){
      c.PB(P(l,r,b[j].p));
      continue;
    }
    if(j==nb||b[j].l>l+eps){c.PB(P(l,r,a[i].p));continue;}
    if(!a[i].p||!b[j].p){c.PB(P(l,r,a[i].p+b[j].p));continue;}
    double m,mid;
    while(l+eps<r){
      m=pos(e[a[i].p],e[b[j].p],l,r);
      mid=(l+m)/2;
      if(e[a[i].p].f(mid)>e[b[j].p].f(mid)){
        c.PB(P(l,m,a[i].p));
      }else{
        c.PB(P(l,m,b[j].p));
      }
      l=m;
    }
  }
  for(i=0,k=c.size();i<k;i=j){
    for(j=i;j<k&&c[i].p==c[j].p;j++);
    f.PB(P(c[i].l,c[j-1].r,c[i].p));
  }
}
void build(int x,int a,int b){
  if(a==b){
    v[x].PB(P(-N,::a[a][0],0));
    v[x].PB(P(::a[a][0],2*::a[a][1]-::a[a][0],a));
    v[x].PB(P(2*::a[a][1]-::a[a][0],N,0));
    return;
  }
  int mid=(a+b)>>1;
  build(x<<1,a,mid),build(x<<1|1,mid+1,b);
  merge(v[x],v[x<<1],v[x<<1|1]);
}
inline void query(const vector<P>&v,int o){
  int l=0,mid,r=v.size()-1;
  while(l<=r){
    mid=(l+r)>>1;
    if(v[mid].r+eps<o)l=mid+1;
    else if(v[mid].l-eps>o)r=mid-1;
    else{
      ans=max(ans,e[v[mid].p].f(o));
      return;
    }
  }
}
void ask(int x,int a,int b){
  if(A<=a&&b<=B){
    query(v[x],C);
    query(v[x],D);
    return;
  }
  int mid=(a+b)>>1;
  if(A<=mid)ask(x<<1,a,mid);
  if(B>mid)ask(x<<1|1,mid+1,b);
}
int main(){
  read(n);
  for(i=1;i<=n;i++){
    int p,x,y;
    read(p),read(x),read(y);
    KD::init(i,x,y);
    a[i][0]=p,a[i][1]=x,a[i][2]=y;
    e[i]=E(p,x,y,p-x,y);
  }
  KD::root=KD::build(1,n,0);
  build(1,1,n);
  read(m);
  while(m--){
    read(A),read(B),read(C),read(D);
    ans=KD::query(A,B,C,D);
    ask(1,1,n);
    printf("%.6f\n",ans);
  }
  return 0;
}

  

posted @ 2016-08-12 22:54  Claris  阅读(649)  评论(0编辑  收藏  举报