zoukankan      html  css  js  c++  java
  • 【BZOJ1576】【USACO2009 Jan】 安全路经Travel

    安全路径

    题意

    Solution

    嗯,首先既然不能经过最后一条边,那么我们考虑建出一个最短路树

    然后非树边(u,v,w),只能影响到(u->v)这个路径上的点,因为只能往回跑

    那么考虑怎么更新。一个显然的办法就是把边按照某种顺序排列,然后用并查集标记一下哪个点访问过了,可以做到(O(n))

    那么按照什么顺序排序呢?我们设一个点(u)到1的距离(即最短路长度)为(dis_u)

    那么对于一条非树边(u->v),设路径上其中一个点为(x),那么这个“不经过最后一条边的次短路”的长度即为(dis_u+dis_v+w-dis_x)

    然后我们按照(dis_u+dis_v+w)排序,就可以快乐维护了

    code:

    #include<bits/stdc++.h>
    using namespace std;
    struct qwq{
        int u;
        int v;
        int w;
        int nxt;
    }edge[400010],e[400010];
    int head[400010];
    int cnt=-1;
    void add(int u,int v,int w){
        edge[++cnt].nxt=head[u];
        edge[cnt].u=u;
        edge[cnt].v=v;
        edge[cnt].w=w;
        head[u]=cnt;
    }
    void add1(int u,int v,int w){
        e[++cnt].nxt=head[u];
        e[cnt].u=u;
        e[cnt].v=v;
        e[cnt].w=w;
        head[u]=cnt;
    }
    struct QAQ{
        int v,w;
        bool operator <(const QAQ& tmp)const{
            return w>tmp.w;
        }
    };
    int dis[400010];
    int vis[400010];
    int n,m;
    void dijkstra(int s){
        for(int i=1;i<=n;++i)dis[i]=INT_MAX;
        dis[s]=0;
        priority_queue<QAQ> q;
        q.push((QAQ){s,0});
        while(!q.empty()){
            QAQ u=q.top();
            q.pop();
            int v=u.v,w=u.w;
            if(w!=dis[v])continue;
            for(int i=head[v];~i;i=edge[i].nxt){
                int tv=edge[i].v,tw=edge[i].w;
                if(dis[tv]>dis[v]+tw){
                    vis[tv]=i;
                    dis[tv]=dis[v]+tw;
                    q.push((QAQ){tv,dis[tv]});
                }
            }
        }
    }
    struct dat{
        int u,v,w;
        int du,dv;
    }a[400010];
    bool cmp(dat a,dat b){
        return a.w+a.du+a.dv<b.w+b.du+b.dv;
    }
    int tot;
    int f[400010][32];
    bool pd[400010];
    void rebuild(){
        memset(head,-1,sizeof(head));
        int tmp=cnt;
        cnt=-1;
        for(int i=2;i<=n;++i){
            int u=edge[vis[i]].u,v=edge[vis[i]].v,w=edge[vis[i]].w;
            add1(u,v,w);
            add1(v,u,w);
            pd[vis[i]]=true;
        }
        for(int i=0;i<=tmp;++i){
            if(!pd[i]&&!pd[i^1]){
                a[++tot].u=edge[i].u;
                a[tot].v=edge[i].v;
                a[tot].w=edge[i].w;
                a[tot].du=dis[edge[i].u];
                a[tot].dv=dis[edge[i].v];
                pd[i]=true;
            }
        }
    }
    int dep[400010];
    void dfs(int u){
        for(int i=1;i<=31;++i){
            f[u][i]=f[f[u][i-1]][i-1];
        }
        for(int i=head[u];~i;i=e[i].nxt){
            int v=e[i].v;
            if(v==f[u][0])continue;
            f[v][0]=u;
            dep[v]=dep[u]+1;
            dfs(v);
        }
    }
    int LCA(int x,int y){
        if(dep[x]<dep[y])swap(x,y);
        int d=dep[x]-dep[y];
        for(int i=0;i<=31;++i){
            if(d&(1<<i)){
                x=f[x][i];
            }
        }
        if(x==y){
            return x;
        }
        for(int i=31;i>=0;--i){
            if(f[x][i]==f[y][i])continue;
            x=f[x][i],y=f[y][i];
        }
        return f[x][0];
    }
    int fa[400010];
    int getfa(int x){
        return fa[x]==x?x:fa[x]=getfa(fa[x]);
    }
    int ans[400010];
    int main(){
        memset(head,-1,sizeof(head));
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;++i){
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);
            add(v,u,w);
        }
        dijkstra(1);
        rebuild();
        dfs(1);
        for(int i=1;i<=n;++i){
            fa[i]=i;
        }
        sort(a+1,a+1+tot,cmp);
        for(int i=1;i<=tot;++i){
            int u=a[i].u,v=a[i].v;
            int sum=a[i].w+a[i].du+a[i].dv;
            int lca=LCA(u,v);
            while(dep[u]>dep[lca]){
                int tmp=getfa(u);
                if(tmp==lca)break;
                if(tmp==u){
                    tmp=fa[u]=f[u][0];
                    ans[u]=sum;
                }
                u=tmp;
            }
            while(dep[v]>dep[lca]){
                int tmp=getfa(v);
                if(tmp==lca)break;
                if(tmp==v){
                    tmp=fa[v]=f[v][0];
                    ans[v]=sum;
                }
                v=fa[v];
            }
        }
        for(int i=2;i<=n;++i){
            printf("%d
    ",ans[i]?ans[i]-dis[i]:-1);
        }
    }
    

    TMD考试的时候dij的堆打反了,然后T了,只有暴力分QAQ

  • 相关阅读:
    第三十七节 log日志模块
    第三十六节 更新备注信息
    第三十五节 取消关注的股票
    第三十四节 路由添加正则功能以及添加关注功能
    第三十三节 通过带有参数的装饰器完成路由功能
    第三十二节 带有参数的装饰器
    Web_CSS
    Web_HTML
    Python操作MySQL
    MySQL_索引原理
  • 原文地址:https://www.cnblogs.com/youddjxd/p/11768295.html
Copyright © 2011-2022 走看看