zoukankan      html  css  js  c++  java
  • 「JOI 2016 Final」铁路票价

    博主的 BiBi 时间

    这道题的暴力我竟然打了 (SPFA)。。。(真·降智)

    Solution

    首先,如果这条边不在最短路上时,它之后也不会有任何贡献。那么之后的边就是指在最短路上的边。

    我们可以确定,当一条边被加上权值时,这条边相当于被删除了。因为它再也不可能是最短路了。

    可以发现,当一个点前面的最短路边都被删了,那么这个点往后延伸的边也是没用的了。(感觉有点像拓扑)

    接下来就可以码出来了,首先我们跑一遍 (BFS),这样通过 (dis) 数组的比较就可以判断是否是在最短路上的边,再搞一个类似入度的东西就好了。

    时间复杂度应该是 (O(m*2))

    Code

    #include <cstdio>
    #include <queue>
    #include <iostream>
    using namespace std;
    
    const int N = 1e5 + 5;
    
    bool vis[N << 1];
    int u[N << 1], v[N << 1], in[N], cnt, ans, n, m, Q, dis[N], goal, dot[N << 2], nxt[N << 2], head[N];
    queue <int> q;
    
    void addEdge(const int u, const int v) {
        dot[++ cnt] = v, nxt[cnt] = head[u], head[u] = cnt;
    }
    
    void bfs() {
        q.push(1); dis[1] = 1;
        while(! q.empty()) {
            int u = q.front(); q.pop();
            for(int i = head[u]; i; i = nxt[i]) {
                int v = dot[i];
                if(! dis[v]) dis[v] = dis[u] + 1, q.push(v);
            }
        }
    }
    
    void del() {
        q.push(goal);
        while(! q.empty()) {
            int e = q.front(); q.pop();
            if(vis[e]) continue;//这里是时间复杂度的保证,显然删过一次就不用再删了
            vis[e] = 1;
            int p = v[e]; -- in[p];
            if(in[p] == 0) {
                ++ ans;
                for(int i = head[p]; i; i = nxt[i])
                    if(dis[p] + 1 == dis[dot[i]]) q.push(i + 1 >> 1);
            }
        }
    }
    
    int main() {
        //freopen("price.in", "r", stdin); freopen("price.out", "w", stdout);
        scanf("%d %d %d", &n, &m, &Q);
        for(int i = 1; i <= m; ++ i) {
            scanf("%d %d", &u[i], &v[i]);
            addEdge(u[i], v[i]), addEdge(v[i], u[i]);
        }
        bfs();
        for(int i = 1; i <= n; ++ i)
            for(int j = head[i]; j; j = nxt[j])
                if(dis[i] + 1 == dis[dot[j]]) ++ in[dot[j]];
        for(int i = 1; i <= m; ++ i)
            if(dis[u[i]] > dis[v[i]]) swap(u[i], v[i]);
        while(Q --) {
            scanf("%d", &goal);
            if(dis[u[goal]] + 1 == dis[v[goal]]) del();
            printf("%d
    ", ans);
        }
        return 0;
    }
    
  • 相关阅读:
    vue.extend 拓展
    leetcode-166-分数到小数(用余数判断有没有出现小数的循环体)
    leetcode-165-比较版本号
    leetcode-162-寻找峰值
    vector.clear()不能用来清零
    leetcode-209-长度最小的子数组
    leetcode-201-数字范围按位与
    完全多部图的判断(个人思考)
    leetcode-200-岛屿的个数(dfs找所有的连通分量)
    leetcode-151-翻转字符串里的单词
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/12831138.html
Copyright © 2011-2022 走看看