zoukankan      html  css  js  c++  java
  • CF843D Dynamic Shortest Path

    CF843D Dynamic Shortest Path

    洛谷评测传送门

    题目描述

    You are given a weighted directed graph, consisting of nn vertices and mm edges. You should answer qq queries of two types:

    • 1 v — find the length of shortest path from vertex 11 to vertex vv .
    • 2 c l_{1} l_{2} ... l_{c}l1 l2 ... l**c — add 11 to weights of edges with indices l_{1},l_{2},...,l_{c}l1,l2,...,l**c .

    输入格式

    The first line of input data contains integers nn , mm , qq ( 1<=n,m<=10^{5}1<=n,m<=105 , 1<=q<=20001<=q<=2000 ) — the number of vertices and edges in the graph, and the number of requests correspondingly.

    Next mm lines of input data contain the descriptions of edges: ii -th of them contains description of edge with index ii — three integers a_{i}a**i , b_{i}b**i , c_{i}c**i ( 1<=a_{i},b_{i}<=n1<=a**i,b**i<=n , 0<=c_{i}<=10^{9}0<=c**i<=109 ) — the beginning and the end of edge, and its initial weight correspondingly.

    Next qq lines of input data contain the description of edges in the format described above ( 1<=v<=n1<=v<=n , 1<=l_{j}<=m1<=l**j<=m ). It's guaranteed that inside single query all l_{j}l**j are distinct. Also, it's guaranteed that a total number of edges in all requests of the second type does not exceed 10^{6}106 .

    输出格式

    For each query of first type print the length of the shortest path from 11 to vv in a separate line. Print -1, if such path does not exists.

    题意翻译

    题意翻译

    有一张nn个点mm条边的有向带权图,你需要回答如下的qq个问题

    1. 1 v1 v 询问以11为起点到vv的最短路
    2. 2 c2 c l_1l1 l_2l2 ... l_cl**c 对于 l_1l1 l_2l2 ... l_cl**c 的边的边权增加1

    输入格式

    第一行3个整数n, m, q (1 leq n, m leq 10^5; 1 leq q leq 2000)n,m,q(1≤n,m≤105;1≤q≤2000),意义如上.

    接下来mm第i + 1i+1行描述第ii条边,每一行三个整数u, v, c (1 leq u, v leq n; 0 leq c leq 10^9)u,v,c(1≤u,vn;0≤c≤109)表示边的起点,终点以及边权.

    接下来qq行描述q个询问,每个询问保证1 leq v leq n1≤vn且1 leq l_i leq m1≤l**im,单组第二种询问保证l_il**i不重复,并且保证所有第二种询问的边数不超过10^6106.

    输出格式

    对于每组第一种询问,输出1行表示从1到vv的最短路.如果最短路不存在,输出-1−1.

    输入输出样例

    输入 #1复制

    输出 #1复制

    输入 #2复制

    输出 #2复制

    说明/提示

    The description of changes of the graph in the first sample case:

    img

    The description of changes of the graph in the second sample case:

    img

    题解:

    2019.11.1模拟赛T3 50分场

    一开始觉得正解应该使用数据结构优化一下,但是并不知道用什么数据结构。所以直接暴力修改反复跑最短路。我傻X用了SPFA

    不要幻想了,一定会T。

    正解:

    因为跑很多遍DIJ一定会T,这不是你加不加优化就能改变的了的。

    所以我们想一下,能不能只跑一遍DIJ。

    跟着这个思路,我们发现:由于是单源最短路,所以对于更改的边权,只会更改一部分节点的最短路。所以我们试着只跑一遍DIJ,然后在这个已经被处理出来的初始状态下的最短路进行修改。

    具体怎么办呢?

    我们设置(f[i])表示(i)点的最短路距离增加量。对于增加值,我们开一个桶。这个桶可以使用(queue)来实现。这个队列里存的是这个距离增加量的节点编号们。那么我们从这些点中进行扩展。这次的扩展需要引入新边权(因为(val)已经被修改过了,所以扩展增量的边权应该被定义成(dist[x]-dist[y]+val[i]))因为我们一次性增加了(c)条边,所以需要把(c)(n-1)(最短路路径是树)做一下比较,如果这个增量比他俩的最小值还要小,说明还有后续的更新,再把它压入桶里进行继续松弛。

    这样就完成了修改的过程。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #define int long long
    using namespace std;
    const int maxn=1e5+10;
    const int INF=0x3f3f3f3f3f3f3f3f;
    int n,m,Q;
    int tot,head[maxn],val[maxn],nxt[maxn],to[maxn];
    priority_queue<pair<int,int> >q;
    int v[maxn],dist[maxn];
    queue<int> t[maxn];
    int f[maxn],maxx;
    void add(int x,int y,int z)
    {
        to[++tot]=y;
        nxt[tot]=head[x];
        val[tot]=z;
        head[x]=tot;
    }
    void dijkstra()
    {
        memset(dist,0x3f,sizeof(dist));
        memset(v,0,sizeof(v));
        q.push(make_pair(0,1));
        dist[1]=0;
        while(!q.empty())
        {
            int x=q.top().second;
            if(v[x])
            {
                q.pop();
                continue;
            }
            x=q.top().second;q.pop();v[x]=1;
            for(int i=head[x];i;i=nxt[i])
            {
                int y=to[i];
                if(dist[y]>dist[x]+val[i])
                    dist[y]=dist[x]+val[i],q.push(make_pair(-dist[y],y));
            }
        }
    }
    void bfs(int v)
    {
        memset(f,0x3f,sizeof(f));
        f[1]=0;
        t[0].push(1);
        maxx=0;
        for(int i=0;i<=maxx;i++)
            while(!t[i].empty())
            {
                int x=t[i].front();
                t[i].pop();
                if(f[x]<i)
                    continue;
                for(int i=head[x];i;i=nxt[i])
                {
                    int y=to[i];
                    int z=dist[x]+val[i]-dist[y];
                    if(f[y]>f[x]+z)
                    {
                        f[y]=f[x]+z;
                        if(f[y]<=min(v,n-1))
                        {
                            t[f[y]].push(y);
                            maxx=max(maxx,f[y]);
                        }
                    }
                }
            }
    }
    signed main()
    {
        scanf("%I64d%I64d%I64d",&n,&m,&Q);
        for(int i=1;i<=m;i++)
        {
            int x,y,z;
            scanf("%I64d%I64d%I64d",&x,&y,&z);
            add(x,y,z);
        }
        dijkstra();
        while(Q--)
        {
            int opt,v,c;
            scanf("%I64d%I64d",&opt,&v);
            if(opt==1)
            {
                if(dist[v]==INF)
                {
                    puts("-1");
                    continue;
                }
                printf("%I64d
    ",dist[v]);
            }
            else
            {
                for(int i=1;i<=v;i++)
                {
                    int a;
                    scanf("%I64d",&a);
                    val[a]++;
                }
                bfs(v);
                for(int i=1;i<=n;i++)
                    dist[i]=min(INF,f[i]+dist[i]);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    Weak Event模型
    Dispatcher Queue性能分析
    WPF中ControlTemplate,ItemsPanelTemplate ,DataTemplate
    事件与委托
    DataGrid: 数据项更新并保持多选
    【C#学习笔记】using 三种使用方式
    Python快捷键
    比特率和波特率
    c#winform程序退出的方法
    C#socket通信-----多线程
  • 原文地址:https://www.cnblogs.com/fusiwei/p/11778651.html
Copyright © 2011-2022 走看看