【USACO】安全路径(计数/求和以及最值小探讨)(最有生成树之最短路径树,LCA,最值问题,并查集)

来源:互联网 发布:unity3d怎么导入场景 编辑:程序博客网 时间:2024/06/07 02:58

题目

【问题描述】

  精灵最近在农场上泛滥,他们经常会阻止牛们从农庄(牛棚1)走到别的牛棚(牛i的目的地是牛棚i)。每一个精灵只认识牛i并且知道牛i一般走到牛棚i的最短路径。所以他们在牛i到牛棚i之间的最后一条牛路上等牛i。当然,牛不愿意遇到精灵,所以准备找一条稍微不同的路径从牛棚1走到牛棚i。请你为每一头牛i找出避免精灵的最短路径长度。

  和往常一样,农场上有 n 个牛棚(编号为1..n), m 条双向牛路(编号为 1..m)把牛棚连接起来,能让所有牛到达它们的目的地。牛路 i 连接牛棚 ai 和 bi(1<=ai,bi<=N)并且需要时间 ti(1<=ti<=1000)通过。没有两条牛路连接同样的牛棚,所有牛路满足 ai!=bi。所有数据中,牛 i 使用的牛棚 1 到牛棚 i 的最短路径是唯一的。

【输入格式】

  第一行包含两个空格分开的整数:n,m。之后的 m 行,每行包含三个空格分开的数ai,bi,ti,表示一条牛路连接的 ai,bi 两个牛棚,通过这条牛路的时间为 ti。

【输出格式】

  第 1 到 n-1 行:第 i 行包含一个数,从牛棚 1 到牛棚 i+1 并且避免从牛棚 1 到牛棚 i+1 最短路径上最后一条牛路的最少的时间。如果这样的路径不存在,输出 -1。

【输入样例】

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

【输出样例】

3
3
6

【数据范围】

3<=n<=100000 2<=m<=200000

分析

这道题真的是很好很好的题目
感觉可能思维难度甚至比天天爱跑步还要大,在方法正确的前提下代码量略少

首先来看正解思路
1、最短路径唯一,因此我们要用最短路径生成树
最短路径生成树哎!!!虽然听说过但我第一次用
2、既然是生成树,那么我们就想到加边然后LCA
每次次LCA我们都可以使得那个环上除了LCA外的所有点得到一个最短路外的其他路
这里我们还要先分析:对于次短路,只有一条边不是最短路径生成树上的边
3、这里倍增如果用逐步爬山法并且每次都更新肯定会超时,我们先化简一下表达式
对于一个点它的更新值是dist[u]+dist[v]+w-dist[z],前面三个都只和添加的边有关系
4、由此我们可以直接排序,按照dist[u]+dist[v]+w从小到大排序,这样每个点只需要修改一次
5、如果一个点已经被修改过了,我们就让它指向它的第一个可能需要修改的结点,对于条新增边来说就是它的
LCA(因为不会影响到LCA本身),就变成了大步跳跃,加上路径压缩,实际就是并查集
然后答案就出来啦。。。太太太牛批了
最短路径生成树+LCA+排序+大步跳跃,1,3都是我很不熟悉的,感觉收获良多

再说说怎么被天天爱跑步误导的,因为对于每一条新增的边我们都可以拆成两段。。。
然后就可以用优先队列维护。。。
但是由于不能及时删除,而且RMQ又不能像计数问题一样找一个改变量
然后我觉得可以用线段树呀!!可是少主不会树链剖分呜呜呜呜~~~ (也暂时不打算学^~^)

同时也验证了:不能瞎联想题,不能主观臆断,每道题最好的做法是题目本身,不然写得又多还要错,特别是 对于没有见过的题目,根本无法把握到本质,也不清楚本质和你联想的那道题究竟是不是一样的 而题目又不会完全一样,你也不知道该学到哪一步,总之就是不要瞎联想,不要每次想到一个做法就想灵光一闪抓住了救命稻草一样

吐槽了这几句,我们来看看天天爱跑步的差分为什么和这道题如此天差地别首先它们的共同点就是可以把结果变成对一条树链的影响但是处理方式完全不同
是因为
1、天天爱跑步是一个计数问题,它可以用差分/前缀和/桶等思想非常灵活的维护,但是它又必须把所有情况计算完全,所以一个元素不能落下,可以利用的性质也因此比较多
2、这里实际上是一个最值问题,它根本就不能实现修改或者区间查询(线段树或者还有好多都是可以的,是指少主暂时不能实现啦),但是它的好处就是我们只需要一个元素就够了,这里用排序加并查集的思路比较 新颖,(反正少主遇到排序就要栽,要改!!不仅会在基础的预处理用到,后面随时可能用)

最后,这应该是一个多算法但是相对并列的,因此逐步分析还是不难,就是要有勇气分析,最开始的时候陷在DIJ里面出不来,也是因为低估了题目,实际上是思路没打开。

代码

#include<cmath>#include<queue>#include<cstdio>#include<vector>#include<cctype>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int maxn=1e5+5,maxm=2e5+5,inf=1e9,oo=16;int np,first[maxn];struct edge{    int to,next,w;}E[maxm<<1];void add(int u,int v,int w){    E[++np]=(edge){v,first[u],w};    first[u]=np;}int n,m;void Init(){    int u,v,w;    scanf("%d%d",&n,&m);    for(int i=1;i<=m;i++)    {        scanf("%d%d%d",&u,&v,&w);        add(u,v,w);        add(v,u,w);    }}struct data{    int id,d;    friend bool operator<(data a,data b)    {        return a.d>b.d;    }};int dist[maxn];int fa[maxn][20],dep[maxn];void DIJ1(){    for(int i=1;i<=n;i++)        dist[i]=inf;    dist[1]=0;    priority_queue<data>pq;    pq.push((data){1,0});    while(!pq.empty())    {        data i=pq.top();pq.pop();        if(dist[i.id]<i.d)continue;        for(int j=1;j<=oo;j++)            fa[i.id][j]=fa[fa[i.id][j-1]][j-1];        dep[i.id]=dep[fa[i.id][0]]+1;        for(int p=first[i.id];p;p=E[p].next)        {            int j=E[p].to,w=E[p].w;            if(i.d+w<dist[j])            {                dist[j]=i.d+w;                fa[j][0]=i.id;                pq.push((data){j,dist[j]});            }        }    }}struct data0{    int u,v,len;    friend bool operator<(data0 a,data0 b)    {        return a.len<b.len;    }}_add[maxm<<1];int sz;int LCA(int u,int v){    if(dep[u]<dep[v])swap(u,v);    int delt=dep[u]-dep[v];        for(int j=0;j<=oo;j++)            if(delt&(1<<j))                u=fa[u][j];     if(u==v)return u;    for(int j=oo;j>=0;j--)        if(fa[u][j]!=fa[v][j])            u=fa[u][j],v=fa[v][j];    return fa[u][0];}void ready(){    for(int i=1;i<=n;i++)    {        for(int p=first[i];p;p=E[p].next)        {            int j=E[p].to;            if(fa[j][0]!=i && fa[i][0]!=j && i<j)            {                _add[++sz]=(data0){i,j,dist[i]+dist[j]+E[p].w};            }        }    }    sort(_add+1,_add+sz+1);}int ans[maxn];int pa[maxn];void Initial(int n){    for(int i=1;i<=n;i++)        pa[i]=i;}int find(int x){    return pa[x]==x?x:pa[x]=find(pa[x]);}void solve(){    Initial(n);    memset(ans,-1,sizeof(ans));    for(int i=1;i<=sz;i++)    {        int u=_add[i].u,v=_add[i].v;        int z=LCA(u,v);        u=find(u);        v=find(v);        while(dep[u]>dep[z])        {            ans[u]=_add[i].len-dist[u];            pa[u]=z;            u=find(fa[u][0]);        }        while(dep[v]>dep[z])        {            ans[v]=_add[i].len-dist[v];            pa[v]=z;            v=find(fa[v][0]);        }    }}void out(){    for(int i=2;i<=n;i++)        printf("%d\n",ans[i]);}int main(){    //freopen("in.txt","r",stdin);    //freopen("out.txt","w",stdout);    Init();    DIJ1();    ready();    solve();    out();    return 0;}
阅读全文
1 0
原创粉丝点击