[BZOJ2402]陶陶的难题II

这算是分数规划的一种...?打扰了...

先二分答案,问题转为判定是否存在$\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));
	}
}

猜你喜欢

转载自www.cnblogs.com/jefflyy/p/9251051.html
今日推荐