bzoj3694 最短路 并查集(树链剖分)

来源:互联网 发布:淘宝客服主管培训课程 编辑:程序博客网 时间:2024/06/15 05:39

题意:给出一个图和他的最短路树,让你求不经过最短路最后一条边的最短路。
。。一开始以为直接上次短路,后来发现zz了,并不可以。。
然后%了一发题解。
其实就是要在最短路树之外找一条路径来跑。。
那么假设现在有一条非树边x-y,长度为len。
那么我们对于t=lca(x,y)(假设y在树上x不在),可以把1-i的路径转化为(i在t到y之间)1-t-x-y-i.
这样的路径长度是dis[x]+dis[y]+len-dis[i].
由于最短路固定为只有1条,所以dis[i]固定不变,那么我们要让dis[x]+dis[y]+len最短。
所以我们可以用这个值去更新t-y所有点(不包括t)的最短路长度.
可以用线段树(树链剖分)也可以用并查集。
这里只讲一下并查集。
先把所有非树边排个序然后逐个更新。
然后我们发现已经被更新过的点不可能被更新(代价越来越大)。
所以我们可以用并查集维护个已经被更新过的lca。
一点都不觉得树剖显然(,可能我比较蠢

#include<cstdio>#include<algorithm>#include<cstring>#include<iostream>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)using namespace std;const int N=2e5+5;int n,m;int tot,head[N],next[N],go[N],val[N],f[N],cnt;int fa[N],bel[N],dis[N],h[N];struct node{    int x,y,l,len;}edge[N];inline void add(int x,int y,int z){    go[++tot]=y;    val[tot]=z;    next[tot]=head[x];    head[x]=tot;}inline void dfs(int x,int fat,int dep){    h[x]=dep;    fa[x]=fat;    for(int i=head[x];i;i=next[i])    {        int v=go[i];        if (v!=fat)        {            dis[v]=dis[x]+val[i];            dfs(v,x,dep+1);        }    }}inline int find(int x){    if (x==f[x])return x;    else return f[x]=find(f[x]);}inline bool cmp(node a,node b){    return a.len<b.len;}int main(){    scanf("%d%d",&n,&m);    fo(i,1,m)    {        int a,b,l,t;        scanf("%d%d%d%d",&a,&b,&l,&t);        if (t==1)        add(a,b,l),add(b,a,l);        else         edge[++cnt].x=a,edge[cnt].y=b,edge[cnt].l=l;    }    dfs(1,0,1);    fo(i,1,cnt)    edge[i].len=edge[i].l+dis[edge[i].x]+dis[edge[i].y];    sort(edge+1,edge+1+cnt,cmp);    fo(i,1,n)f[i]=i;    fo(i,1,cnt)    {        int x=edge[i].x,y=edge[i].y;        int fx=find(x),fy=find(y);        int lastx=0,lasty=0;        while (fx!=fy)        {            if (h[fx]<h[fy])swap(x,y),swap(fx,fy),swap(lastx,lasty);            if (!bel[x])            {                bel[x]=i;                if (lastx)f[lastx]=x;            }            else if (lastx)f[lastx]=x;            lastx=fx;            x=fa[lastx];            fx=find(x);        }    }    if (bel[2])printf("%d",edge[bel[2]].len-dis[2]);    else printf("-1");    fo(i,3,n)    if (bel[i])printf(" %d",edge[bel[i]].len-dis[i]);    else printf(" -1");    return 0;}
0 0
原创粉丝点击