秋哥是saber控,每次saber都很难,但是还有两种颜色的saber没出。
有一棵 n 个点的树,每个点有四个权值 x,y,p,q,给出 m 个询问(a,b),假设 i,j 为 a 到
b 的路径上的可以重合的两个点,求(yi+qj)/(xi+pj)的最大值。
二分答案,就化出了(x,y)与(p,q)分开的式子,分别对此两式求最大值判断,用斜率的经典分析来看(x,y)
若有一k比i优,则
yk-ans*xk>=yi-ans*xi
yk-yi>=ans*(xk-xi)
(yk-yi)/(xk-xi)>=ans
因此维护一个斜率单减的队列,每次二分<ans的位置即可找到当前区间最大值,可是这是一颗树,很自然想到树链剖分,但是整个区间二分肯定包含非此路径节点,于是用线段树维护恰好包含的区间,每个节点还得额外储存队列,这里面有多少log我也不想搞清了,反正最外面那层二分不改成迭代对于秋哥的数据会卡着时间超3个点。
#include <cstdio>
#include <cstring>
#include <cstdlib>
const int oo=1073741819,maxn=100000;
const double eps=1e-3;
int t[2],rt[maxn],f[maxn],d[maxn],next[maxn],sora[maxn],tail[maxn],o[maxn],s1,ss,n,m,p[maxn],up[maxn],m1;
double sum[2],ans[2];
struct lisan{int o,d,i;}b[65536];
struct room{double x,y;}u[2][300000];
struct inf{double x,y,p,q;}a[maxn];
inline double max(double x,double y) {return (x>y) ? x : y;}
struct seg
{
int h,r,k;
double check(room a,room b) {return (b.y-a.y)/(b.x-a.x);}
inline void ori(int l1,int r1,int l2,int r2)
{
room ne;
h=r=++t[k];
for (r--;(((l1<=r1)&&(r1))||((l2<=r2)&&(r2)));) {
if (((u[k][l1].x<u[k][l2].x)&&(l1<=r1))||(l2>r2)) ne=u[k][l1],l1++;else ne=u[k][l2],l2++;
for (;(h<r)&&(check(u[k][r],ne)>check(u[k][r-1],u[k][r]));r--) ;
u[k][++r]=ne;
}
if (h>r) r=0,h=1;else t[k]=r;
}
inline double search(double x)
{
int ll,rr,mid;
for (ll=h+1,rr=r;ll<=rr;) {
mid=(ll+rr)>>1;
if (check(u[k][mid-1],u[k][mid])>x) ll=mid+1;else rr=mid-1;
}
if (ll<=r) return max(u[k][ll-1].y-x*u[k][ll-1].x,u[k][ll].y-x*u[k][ll].x);
else return u[k][ll-1].y-x*u[k][ll-1].x;
}
}c[2][65536];
inline void dfs(int x,int y,int dep)
{
int i,ne;
rt[x]=y,f[x]=1,d[x]=dep;
int max=-oo,maxi=0;
for (i=x;next[i]!=0;) {
i=next[i],ne=sora[i];
if (ne!=y) {
dfs(ne,x,dep+1),f[x]+=f[ne];
if (f[ne]>max) max=f[ne],maxi=ne;
}
}
if (maxi!=0) o[x]=o[maxi];else o[x]=++s1;
}
inline int cmp(const void *i,const void *j)
{
lisan p=*(lisan *)i,q=*(lisan *)j;
if (p.o!=q.o) return p.o-q.o;
return p.d-q.d;
}
void ori()
{
int i;
for (i=1;i<=n;i++) b[i].i=i,b[i].o=o[i],b[i].d=d[i];
qsort(b+1,n,sizeof(b[1]),cmp);
for (i=1;i<=n;i++) {
p[b[i].i]=i;
if (b[i].o!=b[i-1].o) up[b[i].o]=b[i].i;
}
for (i=1;i<=n;i++) {
c[0][i+m1].h=c[0][i+m1].r=++t[0],c[1][i+m1].h=c[1][i+m1].r=++t[1];
c[0][i+m1].k=0,c[1][i+m1].k=1;
u[0][t[0]].x=a[b[i].i].x,u[0][t[0]].y=a[b[i].i].y,
u[1][t[1]].x=a[b[i].i].p,u[1][t[1]].y=a[b[i].i].q;
}
for (i=m1-1;i>=1;i--) {
c[0][i].k=0,c[1][i].k=1;
c[0][i].ori(c[0][i<<1].h,c[0][i<<1].r,c[0][(i<<1)+1].h,c[0][(i<<1)+1].r);
c[1][i].ori(c[1][i<<1].h,c[1][i<<1].r,c[1][(i<<1)+1].h,c[1][(i<<1)+1].r);
}
}
void origin()
{
int i;
for (m1=1;m1<=n+2;m1<<=1) ;t[0]=t[1]=m1+m1;
for (i=1;i<=n;i++) tail[i]=i;ss=n;
}
inline double ask(int k,int l,int r,double x)
{
double ans;
l+=m1-1,r+=m1+1,ans=-oo;
for (;!(1==(l^r));l>>=1,r>>=1) {
if (0==(l&1)) ans=max(ans,c[k][l+1].search(x));
if (1==(r&1)) ans=max(ans,c[k][r-1].search(x));
}
return ans;
}
inline void updata(int &l,double x)
{
sum[0]=ask(0,p[up[o[l]]],p[l],x);sum[1]=ask(1,p[up[o[l]]],p[l],x);
ans[0]=max(ans[0],sum[0]);ans[1]=max(ans[1],sum[1]);
l=rt[up[o[l]]];
}
inline int find(double x,int l,int r)
{
int e;
ans[0]=ans[1]=-oo;
for (;;) {
if (o[l]==o[r]) {
if (d[l]<d[r]) e=l,l=r,r=e;
sum[0]=ask(0,p[r],p[l],x);sum[1]=ask(1,p[r],p[l],x);
ans[0]=max(ans[0],sum[0]);ans[1]=max(ans[1],sum[1]);
break;
}
else
if (d[up[o[l]]]>=d[up[o[r]]]) updata(l,x);else updata(r,x);
}
if (ans[0]+ans[1]>0) return 1;else return 0;
}
inline void link(int x,int y)
{
ss++,next[tail[x]]=ss,tail[x]=ss,sora[ss]=y;
ss++,next[tail[y]]=ss,tail[y]=ss,sora[ss]=x;
}
inline int equ(double x,double y) {return ((y-x)>-eps)&&((y-x)<eps);}
void init()
{
int i,x,y;
double l,r,mid;
scanf("%d\n",&n);
origin();
for (i=1;i<=n;i++) scanf("%llf",&a[i].x);
for (i=1;i<=n;i++) scanf("%llf",&a[i].y);
for (i=1;i<=n;i++) scanf("%llf",&a[i].p);
for (i=1;i<=n;i++) scanf("%llf",&a[i].q);
for (i=1;i<=n-1;i++) scanf("%d%d",&x,&y),link(x,y);
dfs(1,0,0);
ori();
scanf("%d\n",&m);
for (i=1;i<=m;i++) {
scanf("%d%d\n",&x,&y);
for (l=0,r=100000;!equ(l,r);) {
mid=(l+r)/2;
if (find(mid,x,y)) l=mid;else r=mid;
}
printf("%.4llf\n",l);
}
}
int main()
{
freopen("saber.in","r",stdin);
freopen("saber.out","w",stdout);
init();
return 0;
}