gmoj 6842. 【2020.11.5提高组模拟】淘淘蓝蓝之扮猪吃愉悦

   日期:2020-11-08     浏览:126    评论:0    
核心提示:又是一道有了结论就可以愉快玩耍的题目。这题结论并不是那么显然,要理性推理。

题目

https://gmoj.net/senior/#main/show/6842

题解

发现很难将路径分开维护那一坨式子的贡献啊……那就维护整条路径吧!

结论及证明

这题有一个结论: p o w e r , p o i n t power,point power,point越大,新的 p o i n t point point越大。

证明:
p o i n t ′ = p o i n t + 2 sig ⁡ ( Δ p o w e r ) ( ∣ Δ p o w e r ∣ + 1 − 1 ) − A ⋅ sig ⁡ ( Δ p o i n t ) ( ∣ Δ p o i n t ∣ + 1 − 1 ) = 2 Δ p o w e r ∣ Δ p o w e r ∣ ( ∣ Δ p o w e r ∣ + 1 − 1 ) − A ⋅ Δ p o i n t ∣ Δ p o i n t ∣ ( ∣ Δ p o i n t ∣ + 1 − 1 ) \begin{aligned} point' &=point+2\operatorname{sig}{(\Delta power)}(\sqrt{|\Delta power|+1}-1)-A\cdot \operatorname{sig}{(\Delta point)}(\sqrt{|\Delta point|+1}-1)\\[2ex] &=2\cfrac{\Delta power}{|\Delta power|}(\sqrt{|\Delta power|+1}-1)-A\cdot \cfrac{\Delta point}{|\Delta point|}(\sqrt{|\Delta point|+1}-1) \end{aligned} point=point+2sig(Δpower)(Δpower+1 1)Asig(Δpoint)(Δpoint+1 1)=2ΔpowerΔpower(Δpower+1 1)AΔpointΔpoint(Δpoint+1 1)
f ( x ) = { x ∣ x ∣ ( ∣ x ∣ + 1 − 1 ) , x ≠ 0 0 , x = 0 f(x)=\begin{cases} \cfrac{x}{|x|}(\sqrt{|x|+1}-1),&x\neq 0\\[3ex] 0,&x=0 \end{cases} f(x)=xx(x+1 1),0,x=0x=0
可以用定义法证明 f ( x ) f(x) f(x)增函数

那么 p o i n t ′ = p o i n t + 2 f ( Δ p o w e r ) − A ⋅ f ( Δ p o i n t ) = p o i n t 1 + 2 f ( p o w e r 1 − p o w e r 2 ) − A ⋅ f ( p o i n t 1 − p o i n t 2 ) \begin{aligned} point'&=point+2f(\Delta power)-A\cdot f(\Delta point)\\ &=point_1+2f(power_1-power_2)-A\cdot f(point_1-point_2) \end{aligned} point=point+2f(Δpower)Af(Δpoint)=point1+2f(power1power2)Af(point1point2)
A = 0 A=0 A=0时,由于 p o w e r 2 power_2 power2是定值,因此 p o w e r 1 power_1 power1越大 p o i n t ′ point' point越大,得证。
现在考虑 A = 1 A=1 A=1的情况。

g ( x ) = x − f ( x ) g(x)=x-f(x) g(x)=xf(x)。可以发现它也是一个增函数。
p o i n t ′ = p o i n t 1 + 2 f ( p o w e r 1 − p o w e r 2 ) − f ( p o i n t 1 − p o i n t 2 ) = p o i n t 1 − p o i n t 2 + 2 f ( p o w e r 1 − p o w e r 2 ) − f ( p o i n t 1 − p o i n t 2 ) + p o i n t 2 = p o i n t 2 + 2 f ( p o w e r 1 − p o w e r 2 ) + g ( p o i n t 1 − p o i n t 2 ) \begin{aligned} point'&=point_1+2f(power_1-power_2)-f(point_1-point_2)\\[2ex] &=point_1-point_2+2f(power_1-power_2)-f(point_1-point_2)+point_2\\[2ex] &=point_2+2f(power_1-power_2)+g(point_1-point_2) \end{aligned} point=point1+2f(power1power2)f(point1point2)=point1point2+2f(power1power2)f(point1point2)+point2=point2+2f(power1power2)+g(point1point2)

f ( x ) , g ( x ) f(x),g(x) f(x),g(x)的单调性可以得出结论。

下面是 f ( x ) , g ( x ) f(x),g(x) f(x),g(x)的图像:

做法

有了这个结论,就可以愉快地二分答案+树上DP啦!

对于目前二分出来的 p o w e r 1 power_1 power1,考虑怎么在树上得到最大的 p o i n t point point
可以设 f i f_i fi表示 i 的子树中,从某个叶子节点进来,走到 i 时的最大 p o i n t point point(上面已经证明了 p o i n t point point越大越好,因此很容易转移)

接着 O ( n ) O(n) O(n)旋根就好了,注意判断从同一个叶子节点进出的情况。

CODE

#include<cmath>
#include<cstdio>
using namespace std;
typedef long double LF;
#define inf 500000
#define M 200005
#define N 100005
#define e 1e-8
int fir[N],to[M],nex[M],a[N],b[N],deg[N],son[N][2],A,p0,p1,s;
//a:power; b:point
LF f[N],g[N][2],maxx,P;
inline void inc(int x,int y)
{ 
	++deg[x],++deg[y];
	to[++s]=y,nex[s]=fir[x],fir[x]=s;
	to[++s]=x,nex[s]=fir[y],fir[y]=s;
}
inline int sig(LF x){ return x==0?0:(x<0?-1:1);}
inline LF calc(int k,LF power,LF point)
{ return 2*sig(power-a[k])*(sqrt(abs(power-a[k])+1)-1)-A*sig(point-b[k])*(sqrt(abs(point-b[k])+1)-1);}
void dfs(int k,int fa)
{ 
	g[k][0]=g[k][1]=-inf,son[k][0]=son[k][1]=0;
	if(k>1&&deg[k]==1) return;
	for(int i=fir[k];i;i=nex[i]) if(to[i]!=fa)
	{ 
		dfs(to[i],k);
		if(f[to[i]]>g[k][0])
			g[k][1]=g[k][0],son[k][1]=son[k][0],
			g[k][0]=f[to[i]],son[k][0]=to[i];
		else if(f[to[i]]>g[k][1]) g[k][1]=f[to[i]],son[k][1]=to[i];
	}
	f[k]=g[k][0]+calc(k,P,g[k][0]);
}
void rotate(int k,int fa)
{ 
	if(deg[k]==1&&f[k]>maxx) maxx=f[k];
	LF gk[2],sk[2],fk=f[k],gi[2],si[2],fi;
	gk[0]=g[k][0],sk[0]=son[k][0];
	gk[1]=g[k][1],sk[1]=son[k][1];
	for(int i=fir[k];i;i=nex[i]) if(to[i]!=fa)
	{ 
		gi[0]=g[to[i]][0],si[0]=son[to[i]][0];
		gi[1]=g[to[i]][1],si[1]=son[to[i]][1],fi=f[to[i]];
		if(to[i]==son[k][0]) f[k]=deg[k]==1?p0+calc(k,P,p0):g[k][1]+calc(k,P,g[k][1]);
		if(f[k]>g[to[i]][0])
		{ 
			g[to[i]][1]=g[to[i]][0],son[to[i]][1]=son[to[i]][0];
			g[to[i]][0]=f[k],son[to[i]][0]=k;
			f[to[i]]=f[k]+calc(to[i],P,f[k]);
		}
		else if(f[k]>g[to[i]][1]) g[to[i]][1]=f[k],son[to[i]][1]=k;
		rotate(to[i],k);
		g[to[i]][0]=gi[0],son[to[i]][0]=si[0];
		g[to[i]][1]=gi[1],son[to[i]][1]=si[1];
		g[k][0]=gk[0],son[k][0]=sk[0];
		g[k][1]=gk[1],son[k][1]=sk[1];
		f[k]=fk,f[to[i]]=fi;
	}
}
int main()
{ 
	freopen("pigeatyy.in","r",stdin);
	freopen("pigeatyy.out","w",stdout);
	LF l=-inf,r=inf,mid,ans=0;
	int test,n,x,y;
	scanf("%d%d%d%d%d",&test,&n,&p0,&p1,&A);
	for(int i=1;i<n;++i) scanf("%d%d",&x,&y),inc(x,y);
	for(int i=1;i<=n;++i) scanf("%d%d",a+i,b+i);
	while(l<=r)
	{ 
		mid=(l+r)/2;
		if(n==1) maxx=p0+calc(1,mid,p0);
		else
		{ 
			for(int i=1;i<=n;++i)
				if(deg[i]==1)
				{ 
					f[i]=p0+calc(i,mid,p0);
					if(f[i]>=p1){ r=mid-e,ans=mid;continue;}
				}
				else f[i]=0;
			P=mid,dfs(1,0);
			maxx=0,rotate(1,0);
		}
		if(maxx>=p1) r=mid-e,ans=mid;
		else l=mid+e;
	}
	printf("%.6LF\n",ans);
	return 0;
}
 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服