1576: [Usaco2009 Jan]安全路经Travel 最短路径树+树链剖分+线段树

来源:互联网 发布:四ill农信网络学校 编辑:程序博客网 时间:2024/06/03 07:15

神题Orz。

我们可以先dijkstra求出最短路径树。然后有一些不在树上的边,加入后一定会形成一个环,那么此时就为一些点提供了次短路径。
假设我们加入了一条边(u,v),令t=lca(u,v),对于在链t->v上的点x,我们可以走这样一条路线:1->t->u->v->x,画个图可以发现,此时的长度为dis[u]+len(u,v)+dis[v]-dis[x]。dix[x]是已知的,要使结果最小,我们就要使dis[u]+len(u,v)+dis[v]最小。
然后我们可以用树链剖分和线段树来维护一下这个最小值。

#include<iostream>#include<cstdio>#define inf 1000000007#define N 100005using namespace std;int n,m,cnt,sz,dfn;int head[N],dis[N],from[N],belong[N],deep[N],size[N],id[N],fa[N][20];int u[N<<1],v[N<<1],w[N<<1];bool vis[N],mark[N<<2];int next[N<<2],list[N<<2],key[N<<2],tag[N<<2],l[N<<2],r[N<<2];struct node {int v,id;} heap[N];inline int read(){    int a=0,f=1; char c=getchar();    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}    while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}    return a*f;}inline void insert(int x,int y,int z){    next[++cnt]=head[x];    head[x]=cnt;    list[cnt]=y;    key[cnt]=z;}inline void push(node x){    heap[++sz]=x;    int now=sz;    while (now&&heap[now].v<heap[now>>1].v)    {        swap(heap[now],heap[now>>1]);        now>>=1;    }}inline void pop(){    heap[1]=heap[sz--];    int now=1;    while (now<=(sz>>1))    {        int next=now<<1;        if (next<sz&&heap[next].v>heap[next+1].v) next++;        if (heap[now].v<heap[next].v) return;        swap(heap[now],heap[next]);        now=next;    }}inline void dijkstra(){    for (int i=1;i<=n;i++) dis[i]=inf;    dis[1]=0;    push((node){0,1});    while (sz)    {        int x=heap[1].id; pop();        if (vis[x]) continue; vis[x]=1;        for (int i=head[x];i;i=next[i])            if (dis[list[i]]>dis[x]+key[i])            {                dis[list[i]]=dis[x]+key[i];                mark[from[list[i]]]=0;                 from[list[i]]=i;                 mark[i]=1;                push((node){dis[list[i]],list[i]});            }    }}void dfs1(int x){    for (int i=1;(1<<i)<=deep[x];i++) fa[x][i]=fa[fa[x][i-1]][i-1];    size[x]=1;    for (int i=head[x];i;i=next[i])        if (mark[i])        {            fa[list[i]][0]=x;            deep[list[i]]=deep[x]+1;            dfs1(list[i]);            size[x]+=size[list[i]];        }}void dfs2(int x,int chain){    id[x]=++dfn; belong[x]=chain;    int k=0;    for (int i=head[x];i;i=next[i])        if (mark[i]&&size[list[i]]>size[k]) k=list[i];    if (!k) return;    dfs2(k,chain);    for (int i=head[x];i;i=next[i])        if (mark[i]&&list[i]!=k) dfs2(list[i],list[i]);}inline int lca(int x,int y){    if (deep[x]<deep[y]) swap(x,y);    int t=deep[x]-deep[y];    for (int i=0;(1<<i)<=t;i++)        if ((1<<i)&t) x=fa[x][i];    for (int i=19;i>=0;i--)        if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];    return x==y?x:fa[x][0];}void build(int k,int x,int y){    l[k]=x; r[k]=y; tag[k]=inf;    if (l[k]==r[k]) return;    int mid=l[k]+r[k]>>1;    build(k<<1,x,mid); build(k<<1|1,mid+1,y);}inline void pushdown(int k){    if (l[k]==r[k]|tag[k]==inf) return;    tag[k<<1]=min(tag[k<<1],tag[k]);    tag[k<<1|1]=min(tag[k<<1|1],tag[k]);    tag[k]=inf;}void change(int k,int x,int y,int v){    pushdown(k);    if (x==l[k]&&r[k]==y)    {        tag[k]=min(tag[k],v);        return;    }    int mid=l[k]+r[k]>>1;    if (y<=mid) change(k<<1,x,y,v);    else if (x>mid) change(k<<1|1,x,y,v);    else change(k<<1,x,mid,v),change(k<<1|1,mid+1,y,v);}inline void solve_change(int x,int f,int v){    while (belong[x]!=belong[f])    {        change(1,id[belong[x]],id[x],v);        x=fa[belong[x]][0];    }    if (x!=f) change(1,id[f]+1,id[x],v);}int query(int k,int x){    pushdown(k);    if (l[k]==r[k]) return tag[k];    int mid=l[k]+r[k]>>1;    if (x<=mid) return query(k<<1,x);    else return query(k<<1|1,x);}int main(){    n=read(); m=read();    for (int i=1;i<=m;i++)        u[i]=read(),v[i]=read(),w[i]=read(),insert(u[i],v[i],w[i]),insert(v[i],u[i],w[i]);    dijkstra();    dfs1(1);    dfs2(1,1);    build(1,1,n);    for (int i=1;i<=m;i++)    {        int t=lca(u[i],v[i]);        if (!mark[2*i-1]) solve_change(v[i],t,dis[u[i]]+dis[v[i]]+w[i]);        if (!mark[2*i]) solve_change(u[i],t,dis[u[i]]+dis[v[i]]+w[i]);    }    for (int i=2;i<=n;i++)    {        int t=query(1,id[i]);        if (t==inf) puts("-1"); else printf("%d\n",t-dis[i]);    }    return 0;}
0 0
原创粉丝点击