旅行

题目描述 小C上周末和他可爱的同学小A一起去X湖玩。
X湖景区一共有n个景点,这些景点由n-1条观光道连接着,从每个景点开始都可以通过观光道直接或间接地走到其他所有的景点。小C带着小A从1号景点开始游玩。游览完第一个景点后,先由小C决定下一个游览的景点,他们一起走去那个景点玩。接下来,他们轮流决定他们下一步去哪个景点玩。他们不会选择已经走过的景点,因为重复游览一个景点是无趣的。当他们无法选择下一个景点时,他们就结束旅程。
小C是好动的男孩纸,所以他希望游览的过程尽量长,也就是走过观光道的长度和最大。而小A是文静的女孩纸,她希望游览的过程尽量短。小A和小C都极度聪明,且他们的目光都足够长远,他们做出的决策都是对自己最优的。由于小C在旅游前就仔细研究了X湖景区的地图,他可以在旅行开始前就用自己惊人的数学能力推算出他和小A旅行的路径长度。
小C的梦境是美好的。在他的梦里,他和小A又进行了n-1次旅行,第i次旅行从i+1号点开始,每次也是小C先决定下一个景点,然后小A,然后小C……直到旅行结束。现在小C希望你对于所有n次旅行,求出他和小A旅行的路径长度。 输入 第一行一个正整数n,表示景点的个数。 接下来n-1行,每行三个正整数u,v,c。表示有一条连接u和v的双向观光道,其长度为c。 输出
输出一共N行,每行一个正整数。第i行表示从i号点开始旅行他们走过的路径长度。

样例输入
5
1 2 1
1 3 2
2 4 3
2 5 4
样例输出
4
4
7
6
7
提示
从1号景点开始:

若小C选择走到3号景点,则小A无法选择下一个景点,旅行的路径长度为2

若小C选择走到2号景点,则小A会在4号景点和5号景点中选择更近的4号点,然后小C无法选择下一个景点,旅行结束,旅行的路径长度会是4

所以小C会选择走到2号点,最终的路径长度是4

【数据范围】

对于20%的数据,N ≤ 15

对于60%的数据,N ≤ 3000

对于100%的数据,N ≤ 300000, c[i] ≤ 1e9

设gmax[u]表示小A从u向下走获得的最大价值。
设gmin[u]表示小C从u向下走获得的最小价值。
gmax[u]:=max{gmin[v]+len[i]};
gmin[u]:=min{gmax[v]+len[i]};

在考虑根节点转移,设fmax[u],f[min] 表示向上走向下走最大最小值,转移同理,详见代码。

代码(c++)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#define mod 1000000007
#define N 300005
typedef long long ll;
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
const long long inf=300000000000000;
int Head[N],ret[2*N],Next[2*N],len[2*N];
ll gmin[N],gmax[N],Fmin[N],Fmax[N],ans[N];
ll st[N],lmin[N],lmax[N],rmin[N],rmax[N],tmin[N],tmax[N];
int tot,top,n;
void ins(int u,int v,int l)
{
    ret[++tot]=v;len[tot]=l;
    Next[tot]=Head[u];Head[u]=tot;
}
void dfs(int u,int fa)
{
    gmin[u]=inf;
    for (int i=Head[u];i;i=Next[i])
    {
        if (ret[i]==fa) continue;
        int v=ret[i];
        dfs(v,u);
        gmax[u]=max(gmin[v]+len[i],gmax[u]);
        gmin[u]=min(gmax[v]+len[i],gmin[u]);
    }
    if (gmin[u]==inf) gmin[u]=0;
}
void dp(int u,int fa,int dis)
{
    int l=top+1;
    for (int i=Head[u];i;i=Next[i])
    {
        if (ret[i]==fa) continue;
        int v=ret[i];
        tmax[++top]=gmax[v]+len[i];
        tmin[top]=gmin[v]+len[i];
    }
    int r=top;if (r<l) return;
    lmin[l]=tmax[l];lmax[l]=tmin[l];
    for (int i=l+1;i<=r;i++)
    {
        lmin[i]=min(tmax[i],lmin[i-1]);
        lmax[i]=max(tmin[i],lmax[i-1]);
    }
    rmin[r]=tmax[r];rmax[r]=tmin[r];
    for (int i=r-1;i>=l;i--)
    {
        rmin[i]=min(tmax[i],rmin[i+1]);
        rmax[i]=max(tmin[i],rmax[i+1]);
    }
    int cnt=l;
    for (int i=Head[u];i;i=Next[i])
    {
        if (ret[i]==fa) continue;
        int v=ret[i];
        Fmax[u]=Fmin[fa]+dis;
        if (cnt!=l) Fmax[u]=max(Fmax[u],lmax[cnt-1]);
        if (cnt!=r) Fmax[u]=max(Fmax[u],rmax[cnt+1]);
        Fmin[u]=Fmax[fa]+dis;
        if (cnt!=l) Fmin[u]=min(Fmin[u],lmin[cnt-1]);
        if (cnt!=r) Fmin[u]=min(Fmin[u],rmin[cnt+1]);
        ans[v]=max(Fmin[u]+len[i],gmax[v]);
        dp(v,u,len[i]);
        cnt++;
    }
}
int main()
{
    n=read();
    for (int i=1;i<n;i++)
    {
        int u=read(),v=read(),l=read();
        ins(u,v,l);ins(v,u,l);
    }
    dfs(1,0);ans[1]=gmax[1];Fmin[0]=-inf;Fmax[0]=inf;
    dp(1,0,0);
    for (int i=1;i<=n;i++) printf("%lld\n",ans[i]);
    return 0;
}

代码(pascal)

var
tot,i,n,u,v,l:longint;
ans,gmax,gmin,pmax,pmin:array[0..300033] of int64;
head:array[0..300033] of longint;
ret,next,len:array[0..600006] of longint;
fmax,fmaxp,fmin,fminp:array[-1..300033,1..2] of int64;
procedure ins(u,v,l:longint);
begin
  tot:=tot+1;
  ret[tot]:=v;
  len[tot]:=l;
  next[tot]:=head[u];
  head[u]:=tot;
end;

procedure dfs(u,pre:longint);
var
i,v:longint;
flag:boolean;
begin
  i:=head[u];
  flag:=false;
  while i<>0 do
  begin
    v:=ret[i];
    if v<>pre then
    begin
      flag:=true;
      dfs(v,u);
      if gmin[v]+len[i]>gmax[u] then
      begin
        gmax[u]:=gmin[v]+len[i];
        pmax[u]:=v;
      end;
      if gmax[v]+len[i]<gmin[u] then
      begin
        gmin[u]:=gmax[v]+len[i];
        pmin[u]:=v;
      end;
    end;
    i:=next[i];
  end;
  if flag=false then begin gmax[u]:=0; gmin[u]:=0; end;
end;

procedure find(u,pre,l:longint);
var
i,v:longint;
flag:boolean;
begin
  i:=head[u];
  if fminp[pre,1]<>u then
  begin
    fmax[u,1]:=fmin[pre,1]+l;
    fmaxp[u,1]:=pre;
  end
  else
  begin
    fmax[u,1]:=fmin[pre,2]+l;
    fmaxp[u,1]:=pre;
  end;
  if fmaxp[pre,1]<>u then
  begin
    fmin[u,1]:=fmax[pre,1]+l;
    fminp[u,1]:=pre;
  end
  else
  begin
    fmin[u,1]:=fmax[pre,2]+l;
    fminp[u,1]:=pre;
  end;
  if pre=-1 then ans[u]:=0
            else if fminp[pre,1]<>u then ans[u]:=fmin[pre,1]+l
                                    else ans[u]:=fmin[pre,2]+l;
  while i<>0 do
  begin
    v:=ret[i];
    if v<>pre then
    begin
    if gmin[v]+len[i]>ans[u] then ans[u]:=gmin[v]+len[i];
    if gmin[v]+len[i]>fmax[u,1] then
    begin
      fmax[u,2]:=fmax[u,1];
      fmaxp[u,2]:=fmax[u,1];
      fmax[u,1]:=gmin[v]+len[i];
      fmaxp[u,1]:=v;
    end
    else
    if gmin[v]+len[i]>fmax[u,2] then
    begin
      fmax[u,2]:=gmin[v]+len[i];
      fmaxp[u,2]:=v;
    end;
    if gmax[v]+len[i]<fmin[u,1] then
    begin
      fmin[u,2]:=fmin[u,1];
      fminp[u,2]:=fminp[u,1];
      fmin[u,1]:=gmax[v]+len[i];
      fminp[u,1]:=v;
    end
    else
    if gmax[v]+len[i]<fmin[u,2] then
    begin
      fmin[u,2]:=gmax[v]+len[i];
      fminp[u,2]:=v;
    end;
    end;
    i:=next[i];
  end;
  if fmax[u,2]=300000000000000 then fmax[u,2]:=0;
  if fmin[u,2]=300000000000000 then fmin[u,2]:=0;
  i:=head[u];
  while i<>0 do
  begin
    v:=ret[i];
    if v<>pre then
      find(v,u,len[i]);
    i:=next[i];
  end;
end;

begin
  readln(n);
  for i:=1 to n do
    gmin[i]:=30000000000000;
  for i:=1 to n-1 do
  begin
    readln(u,v,l);
    ins(u,v,l);
    ins(v,u,l);
  end;
  dfs(1,-1);
  fmax[-1,1]:=300000000000000;
  fmax[-1,2]:=300000000000000;
  find(1,-1,0);
  for i:=1 to n do
    writeln(ans[i]);
end.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值