[ 树套树 ] [ 二次函数 ][ neerc2011 flight ] BZOJ2646

取到最大值的位置有 2 种情况:

  • 在二次函数顶点:可用树套树维护。
  • l r 上:建棵线段树,每个节点存区间内所有二次函数的轮廓线,查询时在轮廓线上二分。合并 2 个轮廓线时先求出所有区间,再对每个区间不停求交点。

    #include<bits/stdc++.h>
    using namespace std;
    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();
        for(;c<'0'||c>'9';c=nc());
        for(x=0;c>='0'&&c<='9';x=(x<<3)+(x<<1)+c-48,c=nc());
    }
    typedef double db;
    const int N=50010;
    const int M=8000000;
    const db Eps=1e-10;
    #define pb push_back
    struct node{
        int x,y,p;
        db a,b,c;
        inline db Get(db x){
            return a*x*x+b*x+c;
        }
    }a[N];
    struct Node{
        db l,r;int id;
        Node(db l=0,db r=0,int id=0):l(l),r(r),id(id){}
    };
    int k,n,m,p,x,y;
    int mx,num,X,Y;
    int Rt[N<<2];
    int c[M],ls[M],rs[M];
    db q[N<<2],Q[N<<2],Ans;
    vector<Node>g[N<<2],t;
    void Update(int& x,int l,int r,int y,int z){
        if(!x)x=++num;
        c[x]=z;
        if(l==r)return;
        int Mid=l+r>>1;
        if(y<=Mid)Update(ls[x],l,Mid,y,z);else Update(rs[x],Mid+1,r,y,z);
    }
    int Merge(int x,int y,int l,int r){
        if(!x||!y)return x+y;
        if(l==r)return c[x]>c[y]?x:y;
        int z=++num;
        int Mid=l+r>>1;
        ls[z]=Merge(ls[x],ls[y],l,Mid);
        rs[z]=Merge(rs[x],rs[y],Mid+1,r);
        c[z]=max(c[ls[z]],c[rs[z]]);
        return z;
    }
    void build(int x,int l,int r){
        if(l==r){
            Update(Rt[x],0,mx,a[l].x,a[l].y);
            return;
        }
        int Mid=l+r>>1;
        build(x<<1,l,Mid);build(x<<1|1,Mid+1,r);
        Rt[x]=Merge(Rt[x<<1],Rt[x<<1|1],0,mx);
    }
    int query2(int x,int l,int r,int L,int R){
        if(!x||l>R||r<L)return 0;
        if(l>=L&&r<=R)return c[x];
        int Mid=l+r>>1;
        return max(query2(ls[x],l,Mid,L,R),query2(rs[x],Mid+1,r,L,R));
    }
    int query(int x,int l,int r,int L,int R,int y,int z){
        if(l>R||r<L)return 0;
        if(l>=L&&r<=R)return query2(Rt[x],0,mx,y,z);
        int Mid=l+r>>1;
        return max(query(x<<1,l,Mid,L,R,y,z),query(x<<1|1,Mid+1,r,L,R,y,z));
    }
    inline db Calc(int i,int j,db l,db r){
        node x=a[i],y=a[j];
        db a=x.a-y.a,b=x.b-y.b,c=x.c-y.c;
        if(fabs(a)<Eps){
            if(fabs(b)<Eps)return r;
            db Ans=-c/b;
            if(Ans>l+Eps&&Ans+Eps<r)return Ans;
            return r;
        }
        db d=b*b-a*c*4;
        if(d<-Eps)return r;
        d=sqrt(d);
        db w=(-b-d)/a/2;
        db Ans=r;
        if(w>l+Eps&&w+Eps<r)Ans=w;
        w=(-b+d)/a/2;
        if(w>l+Eps&&w+Eps<r)Ans=min(Ans,w);
        return Ans;
    }
    inline void Merge(vector<Node>&A,vector<Node>&B,vector<Node>&C,int x){
        int la=A.size(),lb=B.size();
        if(!la){
            C=B;return;
        }
        if(!lb){
            C=A;
            return;
        }
        int p1=0,p2=0,L=0;
        for(int i=0;i<la;i++)Q[++L]=A[i].l,Q[++L]=A[i].r;
        for(int i=0;i<lb;i++)Q[++L]=B[i].l,Q[++L]=B[i].r;
        sort(Q+1,Q+L+1);
        int l=0;
        for(int i=1;i<=L;){
            int j=i;
            for(;j<L&&fabs(Q[j+1]-Q[j])<Eps;j++);
            q[++l]=Q[i];i=j+1;
        }
        p1=0;p2=0;t.clear();
        for(int i=1;i<l;i++){
            db L=q[i],R=q[i+1];
            while(p1<la&&A[p1].r+Eps<R)p1++;
            while(p2<lb&&B[p2].r+Eps<R)p2++;
            if((p1==la||A[p1].l>L+Eps)&&(p2==lb||B[p2].l>L+Eps))continue;
            if(p1==la||A[p1].l>L+Eps){
                t.pb(Node(L,R,B[p2].id));
                continue;
            }
            if(p2==lb||B[p2].l>L+Eps){
                t.pb(Node(L,R,A[p1].id));
                continue;
            }
            while(L+Eps<R){
                db w=Calc(A[p1].id,B[p2].id,L,R);
                db Mid=(w+L)/2;
                if(a[A[p1].id].Get(Mid)>a[B[p2].id].Get(Mid))t.pb(Node(L,w,A[p1].id));
                else t.pb(Node(L,w,B[p2].id));
                L=w;
            }
        }
        C.clear();l=t.size();
        for(int i=0;i<l;){
            int j;
            for(j=i;j<l-1&&t[j+1].id==t[i].id;j++);
            C.pb(Node(t[i].l,t[j].r,t[i].id));
            i=j+1;
        }
    }
    void Build(int x,int l,int r){
        if(l==r){
            g[x].pb(Node(a[l].p,a[l].x*2-a[l].p,l));
            return;
        }
        int Mid=l+r>>1;
        Build(x<<1,l,Mid);Build(x<<1|1,Mid+1,r);
        Merge(g[x<<1],g[x<<1|1],g[x],x);
    }
    inline db Work(int x,db w){
        int l=0,r=(int)g[x].size()-1,Ans=r;
        while(l<=r){
            int Mid=l+r>>1;
            if(g[x][Mid].r>w+Eps)r=Mid-1,Ans=Mid;else l=Mid+1;
        }
        return a[g[x][Ans].id].Get(w);
    }
    void Query(int x,int l,int r,int L,int R,int y,int z){
        if(l>R||r<L)return;
        if(l>=L&&r<=R){
            Ans=max(Ans,Work(x,y));
            Ans=max(Ans,Work(x,z));
            return;
        }
        int Mid=l+r>>1;
        Query(x<<1,l,Mid,L,R,y,z);Query(x<<1|1,Mid+1,r,L,R,y,z);
    }
    int main(){
        Read(n);
        for(int i=1;i<=n;i++){
            Read(p);Read(x);Read(y);
            a[i].a=(db)y/(2ll*x*p-1ll*p*p-1ll*x*x);
            a[i].b=-a[i].a*2*x;
            a[i].c=-a[i].a*p*p-a[i].b*p;
            a[i].x=x;a[i].y=y;a[i].p=p;
            mx=max(mx,x*2-p);
        }
        build(1,1,n);
        Build(1,1,n);
        Read(m);
        while(m--){
            Read(x);Read(y);Read(X);Read(Y);
            Ans=query(1,1,n,x,y,X,Y);
            Query(1,1,n,x,y,X,Y);
            printf("%.5lf\n",Ans);
        }
        return 0;
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值