这算是分数规划的一种...?打扰了...
先二分答案,问题转为判定是否存在$\frac{y_i+q_j}{x_i+p_j}\geq k$
整理得$-x_ik+y_i-p_jk+q_j\geq0$,于是我们现在要分别找到($(x_i,y_i)$满足$-x_ik+y_i$最大)和($(p_j,q_j)$满足$-p_jk+q_j$最大)并判断是否满足此式
把这些参数看成直线,直接树剖+线段树维护直线形成的下凸壳即可,查询就在凸壳上二分,总时间复杂度$O(n\log_2^3n\log_2\text{ans})$(二分答案,重链,线段树,凸包上二分),因为后三个$\log$都很难跑满,所以能过
#include<stdio.h> #include<algorithm> using namespace std; typedef double du; const du eps=1e-4,inf=2147483647; bool leq(du a,du b){return a-b<=eps;} struct line{ du k,b; line(du x=0,du y=0){k=x;b=y;} du val(du x){return k*x+b;} }l[2][30010],t[30010]; typedef line*linep; linep ch[2][120010]; bool operator<(line a,line b){return a.k==b.k?a.b>b.b:a.k<b.k;} du its(line a,line b){ return(b.b-a.b)/(a.k-b.k); } int h[30010],to[60010],nex[60010],M,n; void add(int a,int b){ M++; to[M]=b; nex[M]=h[a]; h[a]=M; } int fa[30010],dep[30010],siz[30010],son[30010],pos[30010],bl[30010],rpos[30010]; void dfs(int x){ int i,k=0,mx=0; dep[x]=dep[fa[x]]+1; siz[x]=1; for(i=h[x];i;i=nex[i]){ if(to[i]!=fa[x]){ fa[to[i]]=x; dfs(to[i]); siz[x]+=siz[to[i]]; if(siz[to[i]]>mx){ mx=siz[to[i]]; k=to[i]; } } } son[x]=k; } void dfs(int x,int chain){ bl[x]=chain; pos[x]=++M; rpos[M]=x; if(son[x])dfs(son[x],chain); for(int i=h[x];i;i=nex[i]){ if(to[i]!=fa[x]&&to[i]!=son[x])dfs(to[i],to[i]); } } int build(linep&h,linep a,int l,int r){ int n,i,top; n=r-l+1; for(i=l;i<=r;i++)t[i-l+1]=a[rpos[i]]; sort(t+1,t+n+1); top=0; for(i=1;i<=n;i++){ if(t[i].k==t[i-1].k)continue; while(top>1&&leq(its(t[top-1],t[i]),its(t[top-1],t[top])))top--; top++; t[top]=t[i]; } h=new line[top+1]; for(i=1;i<=top;i++)h[i]=t[i]; return top; } int len[2][120010]; void build(int l,int r,int x){ len[0][x]=build(ch[0][x],::l[0],l,r); len[1][x]=build(ch[1][x],::l[1],l,r); if(l==r)return; int mid=(l+r)>>1; build(l,mid,x<<1); build(mid+1,r,x<<1|1); } du query(du k,int n,line*ch){ int l,r,mid,i; l=1; r=n; while(r-l>3){ mid=(l+r)>>1; if(leq(k,its(ch[mid],ch[mid-1]))) r=mid; else l=mid; } du res=-inf; for(i=l;i<=r;i++)res=max(res,ch[i].val(k)); return res; } du query(int f,int L,int R,du k,int l,int r,int x){ if(L<=l&&r<=R)return query(k,len[f][x],ch[f][x]); int mid=(l+r)>>1; du ans=-inf; if(L<=mid)ans=max(ans,query(f,L,R,k,l,mid,x<<1)); if(mid<R)ans=max(ans,query(f,L,R,k,mid+1,r,x<<1|1)); return ans; } du calc(int f,int x,int y,du k){ du ans=-inf; while(bl[x]!=bl[y]){ if(dep[bl[x]]<dep[bl[y]])swap(x,y); ans=max(ans,query(f,pos[bl[x]],pos[x],k,1,n,1)); x=fa[bl[x]]; } if(pos[x]>pos[y])swap(x,y); return max(ans,query(f,pos[x],pos[y],k,1,n,1)); } du solve(int x,int y){ du l,r,mid,ans,t; l=0; r=100000; while(r-l>eps){ mid=(l+r)*.5; t=calc(0,x,y,mid)+calc(1,x,y,mid); if(leq(0,t)){ l=mid; ans=mid; }else r=mid; } return ans; } int main(){ int m,i,x,y; du t; scanf("%d",&n); for(i=1;i<=n;i++){ scanf("%lf",&t); l[0][i].k=-t; } for(i=1;i<=n;i++)scanf("%lf",&l[0][i].b); for(i=1;i<=n;i++){ scanf("%lf",&t); l[1][i].k=-t; } for(i=1;i<=n;i++)scanf("%lf",&l[1][i].b); for(i=1;i<n;i++){ scanf("%d%d",&x,&y); add(x,y); add(y,x); } dfs(1); M=0; dfs(1,1); build(1,n,1); scanf("%d",&m); while(m--){ scanf("%d%d",&x,&y); printf("%.4lf\n",solve(x,y)); } }