BZOJ1767 : [Ceoi2009]harbingers

设d[i]表示i到1的距离

f[i]=w[i]+min(f[j]+(d[i]-d[j])*v[i])=w[i]+d[i]*v[i]+min(-d[j]*v[i]+f[j])

对这棵树进行点分治,每次递归时的根为x,重心为rt

如果x==rt,则把树中所有点用x暴力更新,然后递归分治

否则,先递归分治x的那部分子树,然后将rt到x路径上所有点维护一个凸壳

然后对树中每一个点,在凸壳上二分更新答案

最后再递归分治其它子树

 

#include<cstdio>
#define N 100010
typedef long long ll;
inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
int n,i,x,y,z,g[N],nxt[N<<1],v[N<<1],w[N<<1],ok[N<<1],ed=1,son[N],f[N],size,now,fa[N],V[N];
int q[N],anc[N],t,ta;
ll ans[N],d[N],W[N];
inline void add(int x,int y,int z){v[++ed]=y,w[ed]=z,nxt[ed]=g[x],ok[ed]=1,g[x]=ed;}
inline void up(ll&x,ll y){if(x>y)x=y;}
inline double pos(int x,int y){return (double)(ans[y]-ans[x])/(double)(d[y]-d[x]);}
void findroot(int x,int pre){
  son[x]=1;f[x]=0;
  for(int i=g[x];i;i=nxt[i])if(ok[i]&&v[i]!=pre){
    findroot(v[i],x),son[x]+=son[v[i]];
    if(son[v[i]]>f[x])f[x]=son[v[i]];
  }
  if(size-son[x]>f[x])f[x]=size-son[x];
  if(f[x]<f[now])now=x;
}
inline void deal(int x){
  int l=1,r=t-1,fin=t,mid;
  while(l<=r){
    mid=(l+r)>>1;
    if((double)V[x]<=pos(q[mid],q[mid+1]))r=(fin=mid)-1;else l=mid+1;
  }
  up(ans[x],W[x]+ans[q[fin]]-d[q[fin]]*V[x]);
}
void dfs(int x){
  W[x]+=d[x]*V[x];
  for(int i=g[x];i;i=nxt[i])if(v[i]!=fa[x])d[v[i]]=d[fa[v[i]]=x]+w[i],dfs(v[i]);
}
void cal(int x,int pre){
  deal(x);
  for(int i=g[x];i;i=nxt[i])if(ok[i]&&v[i]!=pre)cal(v[i],x);
}
void cal2(int x,int y){
  up(ans[x],W[x]+ans[y]-d[y]*V[x]);
  for(int i=g[x];i;i=nxt[i])if(ok[i]&&v[i]!=fa[x])cal2(v[i],y);
}
void solve(int x){
  f[0]=size=son[x],findroot(x,now=0);
  int rt=now,i;
  if(rt!=x){
    for(i=g[rt];i;i=nxt[i])if(v[i]==fa[rt]){ok[i]=ok[i^1]=0,solve(x);break;}
    for(ta=0,i=fa[rt];;i=fa[i]){
      anc[++ta]=i;
      if(i==x)break;
    }
    for(t=0;ta;q[++t]=anc[ta--])while(t>1&&pos(anc[ta],q[t])<pos(q[t],q[t-1]))t--;
    if(rt>1)deal(rt);
    while(t>1&&pos(rt,q[t])<pos(q[t],q[t-1]))t--;
    q[++t]=rt;
    for(i=g[rt];i;i=nxt[i])if(ok[i])cal(v[i],rt);
    for(i=g[rt];i;i=nxt[i])if(ok[i])ok[i^1]=0,solve(v[i]);
  }else for(i=g[x];i;i=nxt[i])if(ok[i])ok[i^1]=0,cal2(v[i],x),solve(v[i]);
}
int main(){
  read(n);
  for(i=1;i<n;i++)read(x),read(y),read(z),add(x,y,z),add(y,x,z);
  for(i=2;i<=n;i++)read(x),read(V[i]),W[i]=x,ans[i]=1LL<<60;
  son[1]=n,dfs(1),solve(1);
  for(i=2;i<=n;i++)printf(i<n?"%lld ":"%lld",ans[i]);
  return 0;
}

  

 

posted @ 2015-01-15 20:25  Claris  阅读(588)  评论(0编辑  收藏  举报