BZOJ 2402 陶陶的难题II (01分数规划+树剖+线段树+凸包+二分)
题目大意:略
一定范围内求最大值,考虑二分答案
设现在选择的答案是$mid$,$max \left \{ \frac{yi+qj}{xi+pj} \right \} \geq mid $
展开可得,$(yi-mid*xi)+(qj-mid*pj)>=0$,只要存在$i,j$使得这个式子成立,说明$mid$能作为答案
题目并没有要求我们不能选择同一个节点,所以$i,j$之间没有任何关联
现在需要求出$max \left \{ yi-mid*xi \right \}$,$q,p$和$x,y$同理
移项,$yi=mid*xi+b$,求$b$的最大值,发现这是一个一次函数的形式
线段树维护树链剖分序,线段树上每个节点都挂一个上凸包,每次用一条斜率为$mid$的直线去切这个凸包即可
总时间$O(nlog^{4}n)$,理论上过不去,但#巨佬说跑不满
1 #include <cmath> 2 #include <vector> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 #define N1 30010 7 #define S1 (N1<<1) 8 #define T1 (N1<<2) 9 #define ll long long 10 #define uint unsigned int 11 #define rint register int 12 #define dd double 13 #define il inline 14 #define inf 233333333 15 using namespace std; 16 17 const dd eps=0.000001; 18 int gint() 19 { 20 int ret=0,fh=1;char c=getchar(); 21 while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();} 22 while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();} 23 return ret*fh; 24 } 25 int n,m; 26 struct Edge{ 27 int to[S1],nxt[S1],head[N1],cte; 28 void ae(int u,int v) 29 {cte++,to[cte]=v,nxt[cte]=head[u],head[u]=cte;} 30 }E; 31 struct node{int id;dd val;}tmp[N1]; 32 int cmp1(node s1,node s2){return s1.val<s2.val;} 33 int stk[N1]; 34 struct SEG{ 35 vector<int>cvh[T1]; 36 void build(int l,int r,int rt,int *A,dd *X,dd *Y) 37 { 38 int i,j,cnt=0,tp=0,mid; 39 for(i=l;i<=r;i++) cnt++,tmp[cnt].id=A[i],tmp[cnt].val=X[A[i]]; 40 sort(tmp+1,tmp+cnt+1,cmp1); 41 stk[++tp]=tmp[1].id; 42 for(i=2;i<=cnt;i++) 43 { 44 j=tmp[i].id; 45 while(tp>1&&(Y[j]-Y[stk[tp-1]])*(X[stk[tp]]-X[stk[tp-1]])>=(Y[stk[tp]]-Y[stk[tp-1]])*(X[j]-X[stk[tp-1]])) tp--; 46 stk[++tp]=j; 47 } 48 for(i=1;i<=tp;i++) cvh[rt].push_back(stk[i]); 49 if(l==r) return; 50 mid=(l+r)>>1; 51 build(l,mid,rt<<1,A,X,Y); 52 build(mid+1,r,rt<<1|1,A,X,Y); 53 } 54 dd cvh_query(int rt,dd K,dd *X,dd *Y) 55 { 56 if(cvh[rt].size()==1) return Y[cvh[rt][0]]-X[cvh[rt][0]]*K; 57 int i,l=1,r=cvh[rt].size()-1,mid,p=0,a,b; 58 a=cvh[rt][0],b=cvh[rt][1]; 59 if((Y[b]-Y[a])<=K*(X[b]-X[a])) return Y[a]-X[a]*K; 60 while(l<=r){ 61 mid=(l+r)>>1,a=cvh[rt][mid-1],b=cvh[rt][mid]; 62 if((Y[b]-Y[a])>=K*(X[b]-X[a])) p=mid,l=mid+1; 63 else r=mid-1; 64 }return Y[cvh[rt][p]]-X[cvh[rt][p]]*K; 65 } 66 dd query(int L,int R,int l,int r,int rt,dd K,dd *X,dd *Y) 67 { 68 if(L<=l&&r<=R) 69 return cvh_query(rt,K,X,Y); 70 int mid=(l+r)>>1; dd ans=-inf; 71 if(L<=mid) ans=max(ans,query(L,R,l,mid,rt<<1,K,X,Y)); 72 if(R>mid) ans=max(ans,query(L,R,mid+1,r,rt<<1|1,K,X,Y)); 73 return ans; 74 } 75 }xy,pq; 76 dd X[N1],Y[N1],P[N1],Q[N1]; 77 namespace cut{ 78 int fa[N1],dep[N1],sz[N1],son[N1],tp[N1]; 79 int st[N1],id[N1],tot; 80 void dfs1(int u,int ff) 81 { 82 for(int j=E.head[u];j;j=E.nxt[j]) 83 { 84 int v=E.to[j]; 85 if(v==ff) continue; 86 dep[v]=dep[u]+1; fa[v]=u; dfs1(v,u); 87 sz[u]+=sz[v]; son[u]=sz[v]>sz[son[u]]?v:son[u]; 88 } 89 sz[u]++; 90 } 91 void dfs2(int u) 92 { 93 st[u]=++tot,id[tot]=u; 94 if(son[u]) tp[son[u]]=tp[u], dfs2(son[u]); 95 for(int j=E.head[u];j;j=E.nxt[j]) 96 { 97 int v=E.to[j]; 98 if(v==fa[u]||v==son[u]) continue; 99 tp[v]=v; dfs2(v); 100 } 101 } 102 dd query(int x,int y,dd K) 103 { 104 dd mxy=-inf,mpq=-inf; 105 while(tp[x]!=tp[y]) 106 { 107 if(dep[tp[x]]<dep[tp[y]]) swap(x,y); 108 mxy=max(mxy,xy.query(st[tp[x]],st[x],1,n,1,K,X,Y)); 109 mpq=max(mpq,pq.query(st[tp[x]],st[x],1,n,1,K,P,Q)); 110 x=fa[tp[x]]; 111 } 112 if(dep[x]>dep[y]) swap(x,y); 113 mxy=max(mxy,xy.query(st[x],st[y],1,n,1,K,X,Y)); 114 mpq=max(mpq,pq.query(st[x],st[y],1,n,1,K,P,Q)); 115 return mxy+mpq; 116 } 117 void init() 118 { 119 dep[1]=1,dfs1(1,-1); 120 tp[1]=1,dfs2(1); 121 xy.build(1,n,1,id,X,Y); 122 pq.build(1,n,1,id,P,Q); 123 } 124 }; 125 126 int main() 127 { 128 scanf("%d",&n); 129 int i,x,y; 130 for(i=1;i<=n;i++) scanf("%lf",&X[i]); 131 for(i=1;i<=n;i++) scanf("%lf",&Y[i]); 132 for(i=1;i<=n;i++) scanf("%lf",&P[i]); 133 for(i=1;i<=n;i++) scanf("%lf",&Q[i]); 134 for(i=1;i<n;i++) x=gint(),y=gint(),E.ae(x,y),E.ae(y,x); 135 cut::init(); 136 scanf("%d",&m); 137 dd L,R,mid,ans=0; 138 while(m--) 139 { 140 x=gint(),y=gint(); 141 L=0,R=1e5; 142 while(R-L>=eps) 143 { 144 mid=(L+R)/2; 145 if(cut::query(x,y,mid)>=0) ans=mid,L=mid+eps; 146 else R=mid-eps; 147 } 148 printf("%.4lf\n",ans); 149 } 150 return 0; 151 }