# ●BZOJ 1767 [Ceoi2009]harbingers

http://www.lydsy.com/JudgeOnline/problem.php?id=1767

$DP[i]=min(DP[j]+(dis_i-dis_j)V_i)+W_i (j是i到根的链上的节点)$
$\quad=min(DP[j]-dis_j*V_i)+dis_i*V_i+W_i$

1).注意到DP时是在DFS遍历树时进行，所以这就保证了dis的单调递增，

2).由于是在树上进行，所以从某个节点回溯之后，要把当时它插入单调栈时造成的影响消除。

#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXN 100050
#define ll long long
using namespace std;
ll W[MAXN],V[MAXN],DP[MAXN],dis[MAXN];
int N;
struct Edge{
Edge(){ent=2;}
}
}E;
struct Mostk{
int s[MAXN],top;
#define Slope(i,j) (1.0*(DP[i]-DP[j])/(dis[i]-dis[j]))
void Reset(){top=0;}
int Find(int i){
static int l,r,mid,ret;
l=2; r=top; ret=top+1;
if(top&&dis[i]==dis[s[top]])
{if(DP[i]<DP[s[top]]) ret=top,r--; else return 0;}
while(l<=r){
mid=(l+r)>>1;
if(Slope(i,s[mid])<Slope(s[mid],s[mid-1])) ret=mid,r=mid-1;
else l=mid+1;
}
return ret;
}
int Query(int i){
static int l,r,mid,ret;
l=2; r=top; ret=1;
while(l<=r){
mid=(l+r)>>1;
if(Slope(s[mid],s[mid-1])>V[i]) r=mid-1;
else ret=mid,l=mid+1;
}
return s[ret];
}
}S;
void DFS(int u,int fa){
int p,oldp,oldsp,oldtop;
oldp=p=S.Find(u);
if(p) oldsp=S.s[p],S.s[p]=u,oldtop=S.top,S.top=p;
int v=E.to[i]; if(v==fa) continue;
dis[v]=dis[u]+E.val[i];
p=S.Query(v);
DP[v]=DP[p]+(dis[v]-dis[p])*V[v]+W[v];
DFS(v,u);
}
if(oldp) S.s[oldp]=oldsp; S.top=oldtop;
}
int main(){
scanf("%d",&N);
for(int i=1,u,v,w;i<N;i++){
scanf("%d%d%d",&u,&v,&w);
}
for(int i=2;i<=N;i++)
scanf("%lld%lld",&W[i],&V[i]);
S.Reset();
DFS(1,0);
for(int i=2;i<=N;i++)
printf(i<N?"%lld ":"%lld",DP[i]);
return 0;
}


Do not go gentle into that good night.
Rage, rage against the dying of the light.
————Dylan Thomas
posted @ 2017-12-30 09:22  *ZJ  阅读(356)  评论(0编辑  收藏  举报