秋哥是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; }