USACO JAN 09 Safe Travel G

[USACO09JAN] Safe Travel G

题面翻译

【题目描述】

给定一张有 \(n\) 个节点,\(m\) 条边的无向图,对于任意的 \(i\)\(2\le i\le n\)),请求出在不经过原来 \(1\) 节点到 \(i\) 节点最短路上最后一条边的前提下,\(1\) 节点到 \(i\) 节点的最短路。

特别地,保证 \(1\) 到任何一个点 \(i\) 的最短路都是唯一的。

保证图中没有重边和自环。

【输入格式】

第一行,两个整数 \(n,m\)

之后 \(m\) 行,每行三个整数 \(a_i,b_i,t_i\) 表示有一条 \(a_i\)\(b_i\),边权为 \(t_i\) 的无向边。

【输出格式】

\(n-1\) 行,第 \(i\) 行表示 \(1\)\(i+1\) 在不经过原来 \(1\) 节点到 \(i+1\) 节点最短路上最后一条边的前提下的最短路。如果最短路不存在,则在对应行输出 -1

翻译贡献者:@cryozwq

题目描述

Gremlins have infested the farm. These nasty, ugly fairy-like

creatures thwart the cows as each one walks from the barn (conveniently located at pasture_1) to the other fields, with cow_i traveling to from pasture_1 to pasture_i. Each gremlin is personalized and knows the quickest path that cow_i normally takes to pasture_i. Gremlin_i waits for cow_i in the middle of the final cowpath of the quickest route to pasture_i, hoping to harass cow_i.

Each of the cows, of course, wishes not to be harassed and thus chooses an at least slightly different route from pasture_1 (the barn) to pasture_i.

Compute the best time to traverse each of these new not-quite-quickest routes that enable each cow_i that avoid gremlin_i who is located on the final cowpath of the quickest route from pasture_1 to

pasture_i.

As usual, the M (2 <= M <= 200,000) cowpaths conveniently numbered 1..M are bidirectional and enable travel to all N (3 <= N <= 100,000) pastures conveniently numbered 1..N. Cowpath i connects pastures a_i (1 <= a_i <= N) and b_i (1 <= b_i <= N) and requires t_i (1 <= t_i <= 1,000) time to traverse. No two cowpaths connect the same two pastures, and no path connects a pasture to itself (a_i != b_i). Best of all, the shortest path regularly taken by cow_i from pasture_1 to pasture_i is unique in all the test data supplied to your program.

By way of example, consider these pastures, cowpaths, and [times]:

1--[2]--2-------+ 
|       |       | 
[2]     [1]     [3] 
|       |       | 
+-------3--[4]--4
TRAVEL     BEST ROUTE   BEST TIME   LAST PATH 
p_1 to p_2       1->2          2         1->2 
p_1 to p_3       1->3          2         1->3 
p_1 to p_4      1->2->4        5         2->4 

When gremlins are present:

TRAVEL     BEST ROUTE   BEST TIME    AVOID 
p_1 to p_2     1->3->2         3         1->2 
p_1 to p_3     1->2->3         3         1->3 
p_1 to p_4     1->3->4         6         2->4 

For 20% of the test data, N <= 200.

For 50% of the test data, N <= 3000.

TIME LIMIT: 3 Seconds

MEMORY LIMIT: 64 MB

输入格式

* Line 1: Two space-separated integers: N and M

* Lines 2..M+1: Three space-separated integers: a_i, b_i, and t_i

输出格式

* Lines 1..N-1: Line i contains the smallest time required to travel from pasture_1 to pasture_i+1 while avoiding the final cowpath of the shortest path from pasture_1 to pasture_i+1. If no such path exists from pasture_1 to pasture_i+1, output -1 alone on the line.

样例 #1

样例输入 #1

4 5 
1 2 2 
1 3 2 
3 4 4 
3 2 1 
2 4 3

样例输出 #1

3 
3 
6

提示

感谢 karlven 提供翻译。

分析

不妨先求出最短路树,由题可得,对于点 $ u $ ,$ u $ 子树一点 $ v $ ,子树外一点 $ w $ ,路径 $ u->v->w->1 $ 是合法的。

即 $ dis_v - dis_u + dis_w + dis_{v->w} $ ,其中 $ dis_{v->w} $ 为该非树边边权,其余皆为根到点的路径长。

$ dis_u $ 可以在遍历时累加,于是将 $ val= dis_v + dis_w + dis_{v->w} $ 看作一个整体,分别记在 $ v, w $ 中,每次取最小即可(没有则为-1)。

如图:

但是还有问题,一条非树边可能连接了 $ u $ 子树的两个节点,这时要去掉该非树边的贡献:

具体而言,在一条非树边两点对应的权值线段树上的 $ val $ +1,在两点的lca $ g $ 对应的权值线段树上的 $ val $ -2。

然后遍历此树,向上合并权值线段树,合并完 $ u $ 子树的线段树后 $ u $ 的答案即为线段树中的最小值 $ val_min $ - $ dis_u $。

即 $ ans_u $ = $ val_{min} $ - $ dis_u $(若为负数则无路径,输出-1即可)。



#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+100;
const ll INF=1e12;
struct edge
{
    int x,y,n;
    ll z;
    bool operator < (const edge &a) const
    {
        return z>a.z;
    }
}e[N<<1];
struct segtree
{
    struct node
    {
        int lc,rc,val;
    }s[N<<6];
    int tot;
    void upd(int &i,ll l,ll r,ll x,int z)
    {
        if(!i)
            i=++tot;
        s[i].val+=z;
        if(l==r)
            return ;
        ll mid=(l+r)>>1;
        if(x<=mid)
            upd(s[i].lc,l,mid,x,z);
        else
            upd(s[i].rc,mid+1,r,x,z);

    }
    void merg(int &i,int &j,ll l,ll r)//i <-- j
    {
        if(i==0 || j==0)
        {
            i+=j;
            return ;
        }
        if(l==r)
        {
            s[i].val+=s[j].val;
            return ;
        }
        ll mid=(l+r)>>1;
        merg(s[i].lc,s[j].lc,l,mid);
        merg(s[i].rc,s[j].rc,mid+1,r);
        s[i].val= s[ s[i].lc ].val + s[ s[i].rc ].val;
    }
    ll que(int i,ll l,ll r)
    {
        if(i==0)
            return 0;
        if(l==r)
            return l;
        ll sum=0;
        ll mid=(l+r)>>1;
        if(s[ s[i].lc ].val >0)
            sum=que(s[i].lc,l,mid);
        else
            sum=que(s[i].rc,mid+1,r);
        return sum;
    }
}T;

priority_queue<edge ,vector<edge> >q;
vector<int >son[N];
int n,m,head[N],cnt=1,dfn;
int deg[N],vis[N],pre[N],h[N];
int f[N][21],dep[N],root[N],st[N];
ll dis[N],ans[N];
void ad(int x,int y,ll z)
{
    e[++cnt].n=head[x];
    e[cnt].y=y;
    e[cnt].z=z;
    e[cnt].x=x;
    head[x]=cnt;
}

void init();
void loading();
void work();
void print();
int main()
{
    init();
    loading();
    work();
    return 0;
}
edge emp;
edge made(int y,ll z)
{
    emp.y=y;
    emp.z=z;
    return emp;
}

void dijk()
{
    ++dfn;
    for(int i=1;i<=n;++i)
    {
        dis[i]=INF;
        ans[i]=-1;
        st[i]=i;
    }
    dis[1]=0;
    q.push( made(1,0) );
    while(!q.empty())
    {
        edge nw=q.top();
        q.pop();
        int u=nw.y;
        if(vis[u]==dfn)
            continue;
        vis[u]=dfn;
        for(int i=head[u],v;i;i=e[i].n)
        {
            v=e[i].y;
            if(dis[v]>dis[u]+e[i].z)
            {
                pre[v]=u;
                dis[v]=dis[u]+e[i].z;
                q.push( made(v,dis[v]) );
            }
        }
    }
}

void init()
{
  	freopen("travel.in","r",stdin);
  	freopen("travel.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1,x,y;i<=m;++i)
    {

        ll z;
        scanf("%d%d%lld",&x,&y,&z);
        ad(x,y,z);
        ad(y,x,z);
    }

}

int fin(int x)
{
    return (st[x]==x)?(x):(st[x]=fin(st[x]));
}

void go(int u)
{
    int he=1,ta=0;
    while(vis[u]<dfn)
    {
        h[++ta]=u;
        u=pre[u];
    }
    for(int i=ta,fa,x,fx,fy;i>=1;--i)
    {
        // h[i] --> h[i-1]
        x=h[i];
        fa=pre[ x ];
        fx=fin(x);
        fy=fin(fa);
        if(fx!=fy)
        st[fx]=fy;
        vis[ x ]=dfn;
        f[x][0]=fa;
        dep[x]=dep[fa]+1;
        ++deg[ fa ];
        son[ fa ].push_back(x);
        for(int j=1;j<=19;++j)
            f[x][j]= f[ f[x][j-1] ][j-1];
    }
}

int lca(int x,int y)
{
    if(x==y)
        return x;
    if(dep[x]<dep[y])
        swap(x,y);
    for(int i=19;i>=0;--i)
        if(dep[ f[x][i] ]>dep[y])
            x=f[x][i];
    if(dep[x]!=dep[y])
        x=f[x][0];
    if(x==y)
        return x;
    for(int i=19;i>=0;--i)
        if(f[x][i] != f[y][i])
        {
            x=f[x][i];
            y=f[y][i];
        }
    return f[x][0];
}

void loading()
{
    dijk();
    ++dfn;
    vis[1]=dfn;
    for(int i=2;i<=n;++i)
        if(vis[i]<dfn)
            go(i);
}

void gotans(int u)
{
    for(int i=0,v;i<deg[u];++i)
    {
        v=son[u][i];
        gotans(v);
        T.merg(root[u],root[v],1ll,INF);
    }
    ans[u]=T.que(root[u],1ll,INF)-dis[u];
}

void work()
{
    for(int i=2,x,y,z,lc;i<=cnt;++i)
    {
        x=e[i].x;
        y=e[i].y;
        z=e[i].z;

        if(f[x][0]==y || f[y][0]==x || ( fin(st[x])!=1 ) || ( fin(st[y])!=1 ) )
            continue;
        lc=lca(x,y);
        //dis[x] + dis[y] +z
        int val=dis[x] + dis[y] +z;
        T.upd(root[x],1ll,INF,val,1);
        T.upd(root[y],1ll,INF,val,1);
        T.upd(root[lc],1ll,INF,val,-2);
    }
    gotans(1);
    print();
}

void print()
{
    for(int i=2;i<=n;++i)
    {
        printf("%d\n",(ans[i]<0)?(-1):(ans[i]));
    }
}

posted @ 2024-12-26 19:29  Glowingfire  阅读(17)  评论(0)    收藏  举报