zoukankan      html  css  js  c++  java
  • CF932F 【Escape Through Leaf】

    ( ext{Solution})

    我们设 (dp_i) 表示编号为 (i) 的节点到达该树叶子节点的最小花费,那么显然我们有以下的转移方程:

    [dp_i=egin{cases}0&i ext{ is leaf}\minlimits_{j in child_s}left{dp_j+a_i imes b_j ight}& ext{Otherwide}\end{cases} ]

    直接转移是 ( ext{O}left(n^2 ight)) 的,考虑如何优化。

    我们令 (dp_j+a_i imes b_j)(y)(a_i)(x) ,则我们可以在二维平面上用 (y=b_j imes x + dp_j) 这条直线表示出一种转移的情况,那么我们求 (minleft{dp_j+a_i imes b_j ight}) 等价于在若干条直线找到一条直线,使其与 (x=a_i) 交点的纵坐标最小,因此可以直接使用李超树维护。

    可以先将树的 dfs 序处理出来,那么 dp 的转移便是一个区间,因此线段树套李超树维护一下就行了。

    ( ext{Code})

    const int N=4e5+5;
    int n,a[N],b[N],dfn[N],low[N],ans[N],cnt;
    
    vector<int> val,lcc,rcc;
    
    struct Edge
    {
    	int v,ne;
    }e[N*2];
    int head[N],tot;
    
    struct Line
    {
    	int k,b;
    }c[N];
    
    inline int f(int id,int v);
    inline void add(int u,int v);
    void dfs1(int u,int fa);
    void dfs2(int u,int fa);
    void build(int x,int l,int r);
    void update1(int x,int l,int r,int p,int v);
    int query1(int x,int l,int r,int L,int R,int v);
    void update2(int x,int l,int r,int v);
    int query2(int x,int l,int r,int v);
    
    signed main()
    {
    	n=read();
    	for(int i=1;i<=n;++i) a[i]=read();
    	for(int i=1;i<=n;++i) b[i]=read();
    	for(int i=1;i<=n-1;++i)
    	{
    		int u=read(),v=read();
    		add(u,v);add(v,u);
    	}
    	c[0].b=1e18;
    	dfs1(1,0);
    	cnt=0;build(1,1,n);
    	for(int i=0;i<=cnt;++i)
    	{
    		val.push_back(0);
    		lcc.push_back(0);
    		rcc.push_back(0);
    	}
    	dfs2(1,0);
    	for(int i=1;i<=n;++i)
    		printf("%lld ",ans[i]);
    	return 0;
    }
    
    inline int f(int id,int v)
    {
    	return c[id].k*v+c[id].b;
    }
    
    inline void add(int u,int v)
    {
    	e[++tot]=(Edge){v,head[u]};
    	head[u]=tot;
    }
    
    void dfs1(int u,int fa)
    {
    	dfn[u]=++cnt;
    	for(int i=head[u];i;i=e[i].ne)
    	{
    		int v=e[i].v;
    		if(v==fa) continue;
    		dfs1(v,u);
    	}
    	low[u]=cnt;
    }
    
    void dfs2(int u,int fa)
    {
    	int fl=1;
    	for(int i=head[u];i;i=e[i].ne)
    	{
    		int v=e[i].v;
    		if(v==fa) continue;
    		dfs2(v,u);fl=0;
    	}
    	if(fl) ans[u]=0;
    	else ans[u]=query1(1,1,n,dfn[u]+1,low[u],a[u]+100001);
    	c[u]=(Line){b[u],ans[u]};
    	update1(1,1,n,dfn[u],u);
    }
    
    void build(int x,int l,int r)
    {
    	cnt=max(cnt,x);
    	if(l==r) return;
    	build(lc,l,mid);
    	build(rc,mid+1,r);
    }
    
    void update1(int x,int l,int r,int p,int v)
    {
    	update2(x,1,200001,v);
    	if(l==r) return;
    	if(p<=mid) update1(lc,l,mid,p,v);
    	else update1(rc,mid+1,r,p,v);
    }
    
    int query1(int x,int l,int r,int L,int R,int v)
    {
    	if(L<=l&&r<=R) return query2(x,1,200001,v);
    	int res=1e18;
    	if(L<=mid) res=min(res,query1(lc,l,mid,L,R,v));
    	if(mid+1<=R) res=min(res,query1(rc,mid+1,r,L,R,v));
    	return res;
    }
    
    void update2(int x,int l,int r,int v)
    {
    	if(l==r)
    	{
    		if(f(v,l-100001)<f(val[x],l-100001))
    			val[x]=v;
    		return;
    	}
    	if(c[v].k>c[val[x]].k)
    	{
    		if(f(v,mid-100001)<f(val[x],mid-100001))
    		{
    			if(!rcc[x])
    			{
    				rcc[x]=++cnt;
    				val.push_back(0);
    				lcc.push_back(0);
    				rcc.push_back(0);
    			}
    			update2(rcc[x],mid+1,r,val[x]),val[x]=v;
    		}
    		else
    		{
    			if(!lcc[x])
    			{
    				lcc[x]=++cnt;
    				val.push_back(0);
    				lcc.push_back(0);
    				rcc.push_back(0);
    			}
    			update2(lcc[x],l,mid,v);
    		}
    	}
    	if(c[v].k<c[val[x]].k)
    	{
    		if(f(v,mid-100001)<f(val[x],mid-100001))
    		{
    			if(!lcc[x])
    			{
    				lcc[x]=++cnt;
    				val.push_back(0);
    				lcc.push_back(0);
    				rcc.push_back(0);
    			}
    			update2(lcc[x],l,mid,val[x]);val[x]=v;
    		}
    		else
    		{
    			if(!rcc[x])
    			{
    				rcc[x]=++cnt;
    				val.push_back(0);
    				lcc.push_back(0);
    				rcc.push_back(0);
    			}
    			update2(rcc[x],mid+1,r,v);
    		}
    	}
    	if(c[v].k==c[val[x]].k)
    	{
    		if(f(v,mid-100001)<f(val[x],mid-100001))
    			val[x]=v;
    		return;
    	}
    }
    
    int query2(int x,int l,int r,int v)
    {
    	if(x==0) return 1e18;
    	int res=f(val[x],v-100001);
    	if(l==r) return res;
    	if(v<=mid) return min(res,query2(lcc[x],l,mid,v));
    	else return min(res,query2(rcc[x],mid+1,r,v));
    }
    
    © 版权声明 文章版权归作者所有,未经允许请勿转载。
  • 相关阅读:
    【试水CAS-4.0.3】第07节_CASclient配置单点登录
    30分钟,让你彻底明白Promise原理
    【你离硅谷只差一步】网易中国创业家大赛项目火热征集中
    21分钟学会写编译器
    Android 模拟器下载、编译及调试
    GitLab 自动触发 Jenkins 构建
    微服务监控探索
    感觉要火!妹子实地采访网易猪厂程序员七夕怎么过
    延迟任务调度系统—技术选型与设计(下篇)
    使用QUIC
  • 原文地址:https://www.cnblogs.com/blackbird137/p/14402433.html
Copyright © 2011-2022 走看看