• 【bzoj2402】陶陶的难题II 【树链剖分+线段树+斜率优化+二分】


    题目大意:
    这里写图片描述
    解法:
    二分答案m,转化为判断性问题。
    (y[i]+q[j])/(x[i]+p[j])>=m
    y[i]+q[j]>=x[i]m+p[j]m
    (y[i]x[i]m)+(q[j]p[j]m)>=0
    这样我们就把答案分成了独立的两部分,两边都取最大即可。以第一部分举例。
    若k比j优,则
    y[k]x[k]m>=y[j]x[j]m
    y[k]y[k]>=x[k]mx[j]m
    y[k]y[j]>=(x[k]x[j])m
    (y[k]y[j])/(x[k]x[j])>=m
    这是一个非常标准的斜率优化的形式。
    这一题是树链上的询问,所以我们可以树链剖分套线段树,线段树上递减维护斜率。我们就递减维护(y[k]y[j])/(x[k]x[j])。先把每个线段树节点的单调递减的斜率处理出来,查询时二分到第一个小于m的斜率就是解。然后在线段树上取个max即可。最后判断一下两部分的和是否大于等于0。
    吐槽:WA的我要死啊!最后把输出四位改成输出五位就A了?你逗我呢?
    代码:

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    using namespace std;
    const int N=30005;
    const double eps=1e-5;
    int n,m,u,v,cnt,head[N],to[N*2],nxt[N*2];
    int idx,siz[N],fa[N],dep[N],son[N],top[N],dfn[N],pos[N];
    double x[N],y[N],p[N],q[N];
    void adde(int u,int v){
        to[++cnt]=v;
        nxt[cnt]=head[u];
        head[u]=cnt;
    }
    void dfs(int u){
        siz[u]=1;
        int v;
        for(int i=head[u];i;i=nxt[i]){
            v=to[i];
            if(v!=fa[u]){
                fa[v]=u;
                dep[v]=dep[u]+1;
                dfs(v);
                siz[u]+=siz[v];
                if(!son[u]||siz[son[u]]<=siz[v]){
                    son[u]=v;
                }
            }
        }
    }
    void dfs(int u,int tp){
        dfn[u]=++idx;
        pos[idx]=u;
        top[u]=tp;
        if(son[u]){
            dfs(son[u],tp);
        }
        int v;
        for(int i=head[u];i;i=nxt[i]){
            v=to[i];
            if(v!=fa[u]&&v!=son[u]){
                dfs(v,v);
            }
        }
    }
    struct data{
        double x,y;
    };
    double getx(data a,data b){
        return b.y-a.y;
    }
    double gety(data a,data b){
        return b.x-a.x;
    }
    struct SegmentTree{
        vector<data> v1[N*4],v2[N*4];
        void build(int o,int l,int r,double *x,double *y){
            if(l==r){
                v1[o].push_back((data){x[pos[l]],y[pos[l]]});
                v2[o].push_back((data){x[pos[l]],y[pos[l]]});
                return;
            }
            int mid=(l+r)/2;
            build(o*2,l,mid,x,y);
            build(o*2+1,mid+1,r,x,y);
            for(int i=0,j=0,k=0;i<r-l+1;i++){
                if(k>=r-mid){
                    v2[o].push_back(v2[o*2][j++]);
                }else if(j>=mid-l+1){
                    v2[o].push_back(v2[o*2+1][k++]);
                }else if(v2[o*2][j].x<v2[o*2+1][k].x){
                    v2[o].push_back(v2[o*2][j++]);
                }else{
                    v2[o].push_back(v2[o*2+1][k++]);
                }
            }
            for(int i=0;i<r-l+1;i++){
                while(v1[o].size()>1&&getx(v1[o][v1[o].size()-1],v2[o][i])*gety(v1[o][v1[o].size()-2],v1[o][v1[o].size()-1])>=getx(v1[o][v1[o].size()-2],v1[o][v1[o].size()-1])*gety(v1[o][v1[o].size()-1],v2[o][i])){
                    v1[o].pop_back();
                }
                v1[o].push_back(v2[o][i]);
            }
        }
        double get(int o,double m){
            int l=0,r=v1[o].size()-1;
            while(l<r){
                int mid=(l+r)/2;
                if(getx(v1[o][mid],v1[o][mid+1])<m*gety(v1[o][mid],v1[o][mid+1])){
                    r=mid;
                }else{
                    l=mid+1;
                }
            }
            return v1[o][r].y-v1[o][r].x*m;
        }
        double query(int o,int l,int r,int L,int R,double m){
            if(L==l&&R==r){
                return get(o,m);
            }
            int mid=(l+r)/2;
            if(R<=mid){
                return query(o*2,l,mid,L,R,m);
            }else if(L>mid){
                return query(o*2+1,mid+1,r,L,R,m);
            }else{
                return max(query(o*2,l,mid,L,mid,m),query(o*2+1,mid+1,r,mid+1,R,m));
            }
        }
    }s1,s2;
    bool check(int u,int v,double m){
        double a=-1e18,b=-1e18;
        while(top[u]!=top[v]){
            if(dep[top[u]]<dep[top[v]]){
                swap(u,v);
            }
            a=max(a,s1.query(1,1,n,dfn[top[u]],dfn[u],m));
            b=max(b,s2.query(1,1,n,dfn[top[u]],dfn[u],m));
            u=fa[top[u]];
        }
        if(dep[u]>dep[v]){
            swap(u,v);
        }
        a=max(a,s1.query(1,1,n,dfn[u],dfn[v],m));
        b=max(b,s2.query(1,1,n,dfn[u],dfn[v],m));
        return a+b>=0;
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%lf",&x[i]);
        }
        for(int i=1;i<=n;i++){
            scanf("%lf",&y[i]);
        }
        for(int i=1;i<=n;i++){
            scanf("%lf",&p[i]);
        }
        for(int i=1;i<=n;i++){
            scanf("%lf",&q[i]);
        }
        for(int i=1;i<n;i++){
            scanf("%d%d",&u,&v);
            adde(u,v);
            adde(v,u);
        }
        dfs(1);
        dfs(1,1);
        s1.build(1,1,n,x,y);
        s2.build(1,1,n,p,q);
        scanf("%d",&m);
        for(int i=1;i<=m;i++){
            scanf("%d%d",&u,&v);
            double l=0,r=1e8;
            while(r-l>eps){
                double mid=(l+r)/2;
                if(check(u,v,mid)){
                    l=mid;
                }else{
                    r=mid;
                }
            }
            printf("%.5lf
    ",l);
        }
        return 0;
    }
  • 相关阅读:
    Java中的CopyOnWrite
    Collection和Collections的区别
    java中值类型与引用类型的关系
    Xml的用途
    js弹框的3种方法
    文件夹重定向失败解决方案
    网络管理人员经常遇到的十个问题(转载)
    QTP之下拉列表单选框…
    Windows脚本宿主对象模型
    QTP报错“缺少对象WScript”
  • 原文地址:https://www.cnblogs.com/2016gdgzoi471/p/9476885.html
Copyright © 2020-2023  润新知