C122 李超树合并+DP CF932F Escape Through Leaf

视频链接:C122 李超树合并+DP CF932F Escape Through Leaf_哔哩哔哩_bilibili

 

 

 

C65【模板】线段树合并 P4556 [Vani有约会]雨天的尾巴 - 董晓 - 博客园 (cnblogs.com)

CF932F Escape Through Leaf

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

#define ll long long
#define N 100005
#define INF 0x3f3f3f3f3f3f3f3f
#define mid ((l+r)>>1)

int h[N],to[N<<1],ne[N<<1],idx;
inline void add(int x,int y){
  ne[++idx]=h[x],to[idx]=y,h[x]=idx;
}
struct line{
  ll k,b;
}p[N];
int rt[N],tot,ls[N<<5],rs[N<<5],id[N<<5];
ll n,a[N],b[N],f[N];

ll Y(int i,ll x){ //求Y值
  return p[i].k*(x-N)+p[i].b; //x-N:修正
}
void change(int &u,int l,int r,int i){ //修改
  if(!u){id[u=++tot]=i; return;}
  if(Y(i,mid)<Y(id[u],mid)) swap(i,id[u]);
  if(Y(i,l)<Y(id[u],l)) change(ls[u],l,mid,i);
  if(Y(i,r)<Y(id[u],r)) change(rs[u],mid+1,r,i);
}
ll query(int u,int l,int r,ll x){ //查询
  if(!u) return INF;
  ll ans=Y(id[u],x);
  if(x<=mid)return min(ans,query(ls[u],l,mid,x));
  else return min(ans,query(rs[u],mid+1,r,x));
}
void merge(int &x,int y,int l,int r){ //合并
  if(!x||!y){x=x|y; return;}
  merge(ls[x],ls[y],l,mid);
  merge(rs[x],rs[y],mid+1,r);
  change(x,l,r,id[y]);  //插入直线id[y]
}
void dfs(int x,int fa){ //递归合并
  for(int i=h[x];i;i=ne[i]){
    int y=to[i];
    if(y==fa) continue;
    dfs(y,x);
    merge(rt[x],rt[y],1,N<<1);
  }
  f[x]=query(rt[x],1,N<<1,a[x]+N);
  if(f[x]==INF) f[x]=0; //修正叶子节点
  p[x]={b[x],f[x]};
  change(rt[x],1,N<<1,x); //插入直线x
}
int main(){
  scanf("%lld",&n);
  for(int i=1;i<=n;++i)scanf("%lld",&a[i]);
  for(int i=1;i<=n;++i)scanf("%lld",&b[i]);
  for(int i=1,x,y;i<n;++i)
    scanf("%d%d",&x,&y),add(x,y),add(y,x);
  dfs(1,0);
  for(int i=1;i<=n;++i)printf("%lld ",f[i]);
}

 

posted @ 2024-05-17 22:08  董晓  阅读(117)  评论(0编辑  收藏  举报