我是靠谱客的博主 靓丽羊,最近开发中收集的这篇文章主要介绍cf932F Escape Through Leaf dp+李超树DescriptionConstraintsSolutionCode,觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
Description
有一棵以 1 号点为根的树,有 n−1 条边 ui,vi,每个点两个权值 Ai,Bi。 你可以从一个点 u 跳到另一个点 v 满足 v 在 u 的子树中,并付出 Au ·Bv 的代价。 定义终止节点为没有任何儿子的节点。对于每个节点,求出从这个点出发到达任意一 个终止节点的最小代价。
Constraints
对于 30% 的数据,n ≤ 5∗103。
对于另外 10% 的数据,∀i Bi = 1。
对于另外 30% 的数据,树是一条链,且除 1 号点外,i 号点的父亲是 i−1。
对于 100% 的数据,2 ≤ n ≤ 105,|Ai|,|Bi|≤ 105。
Solution
考虑dp,设f[i]为第i个点的答案,转移比较显然
可以发现如果把b看成斜率,f看成截距,那么我们实际上在找某一条垂直于x轴的直线与子树内直线的最低交点,这个点显然只在凸壳上
这里写的是李超树合并,然鹅我并不会证复杂度。std给出的是set维护凸壳,启发式合并的做法。
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
typedef long long LL;
const LL INF=1000000000000000LL;
const int N=200005;
struct line {LL k,b;};
struct edge {int y,next;} e[N*2];
struct treeNode {int l,r; line rec;} t[N*51];
int a[N],b[N];
int root[N],tot;
int ls[N],edCnt;
LL f[N];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void add_edge(int x,int y) {
e[++edCnt]=(edge) {y,ls[x]}; ls[x]=edCnt;
e[++edCnt]=(edge) {x,ls[y]}; ls[y]=edCnt;
}
double get_x(line a,line b) {
return (double)(a.b-b.b)/(b.k-a.k);
}
LL get_y(line a,LL x) {
return a.k*x+a.b;
}
void modify(int &now,int tl,int tr,line x) {
if (!now) {
t[now=++tot].rec=x;
return ;
}
if (get_y(t[now].rec,tl)<get_y(x,tl)&&get_y(t[now].rec,tr)<get_y(x,tr)) return ;
if (get_y(t[now].rec,tl)>get_y(x,tl)&&get_y(t[now].rec,tr)>get_y(x,tr)) {
t[now].rec=x; return ;
}
double pos=get_x(t[now].rec,x);
int mid=(tl+tr)>>1;
if (t[now].rec.k<x.k) {
if (pos>mid) {
modify(t[now].r,mid+1,tr,t[now].rec);
t[now].rec=x;
} else modify(t[now].l,tl,mid,x);
} else {
if (pos<mid) {
modify(t[now].l,tl,mid,t[now].rec);
t[now].rec=x;
} else modify(t[now].r,mid+1,tr,x);
}
}
LL query(int now,int tl,int tr,int x) {
if (!now) return INF;
if (tl==tr) return get_y(t[now].rec,x);
int mid=(tl+tr)>>1;
LL tmp,ret=get_y(t[now].rec,x);
if (x<=mid) tmp=query(t[now].l,tl,mid,x);
else tmp=query(t[now].r,mid+1,tr,x);
return std:: min(ret,tmp);
}
int merge(int x,int y,int tl,int tr) {
if (!x||!y) return x+y;
if (tl==tr) {
if (get_y(t[y].rec,tl)<get_y(t[x].rec,tl)) {
t[x].rec=t[y].rec;
}
return x;
}
int mid=(tl+tr)>>1;
t[x].l=merge(t[x].l,t[y].l,tl,mid);
t[x].r=merge(t[x].r,t[y].r,mid+1,tr);
modify(x,tl,tr,t[y].rec);
return x;
}
void dfs(int now,int fa) {
bool flag=true;
for (int i=ls[now];i;i=e[i].next) {
if (e[i].y==fa) continue;
dfs(e[i].y,now);
root[now]=merge(root[now],root[e[i].y],-N,N);
flag=false;
}
if (!flag) f[now]=query(root[now],-N,N,a[now]);
modify(root[now],-N,N,(line) {b[now],f[now]});
}
int main(void) {
freopen("data.in","r",stdin);
freopen("myp.out","w",stdout);
int n=read();
rep(i,1,n) a[i]=read();
rep(i,1,n) b[i]=read();
rep(i,2,n) add_edge(read(),read());
dfs(1,0);
rep(i,1,n) printf("%lldn", f[i]);
return 0;
}
最后
以上就是靓丽羊为你收集整理的cf932F Escape Through Leaf dp+李超树DescriptionConstraintsSolutionCode的全部内容,希望文章能够帮你解决cf932F Escape Through Leaf dp+李超树DescriptionConstraintsSolutionCode所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复