[生气!!&教训] D: Delete(Wannafly挑战赛2)(拓扑+Dijkstra+线段树)

7 篇文章 0 订阅
5 篇文章 0 订阅

D: Delete

链接:https://ac.nowcoder.com/acm/contest/17/D
来源:牛客网
以下表情包来源(百度 http://www.baidu.com

Description

给定一张n个点,m条边的带权有向无环图,同时给定起点S和终点T,一共有q个询问,每次询问删掉某个点和所有与它相连的边之后S到T的最短路,询问之间互相独立(即删除操作在询问结束之后会立即撤销),如果删了那个点后不存在S到T的最短路,则输出-1。

Input

第一行四个正整数表示n,m,S,T,意义如题所述;
接下来m行每行三个正整数x[i],y[i],z[i],表示有一条x[i]到y[i]的有向边,权值为z[i];
第m+1行一个正整数q表示询问次数;
接下来q行每行一个正整数a[i]表示这次询问要删除点a[i]。
n,q <= 10^5
m <= 2*10^5
z[i] <= 10^9

Output

q行每行一个数输出答案,如果删了这个点后不存在S到T的最短路,输出-1

Sample Input

6 7 1 5
1 2 2
2 3 4
3 4 3
4 5 5
3 5 9
1 6 10
6 5 13
4
3
4
2
6

Sample Output

23
15
23
14

这道题真是气死个人了!!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!!

起因 (作死的开始) :

 队友深夜来题,跃跃欲试,于是便一发不可收拾
在这里插入图片描述
拿到题目第一感觉来着不善,但还是有种想AC的冲动,于是就有了接下来一天的故事…

题解与解题历程

上午算法课

 一大早第一节算法课正式开始搞这道题。看到图给的是DAG,又要删除点和边,第一想到先做拓扑排序 (思路都还没有,管他呢,排好再说) 就在排的正爽时,老师突然点我回答问题???

在这里插入图片描述
老师: “Bellman-Ford算法用的是什么思路 ?? "
我的内心:”(没听课 讲到哪了。。?) ??什么思路什么思路?? 老师想要的是什么样的答案??"
我:“额…这就一个BFS的思路,在bfs搜索中不断松弛边的距离,然后可以用…”
老师:" 啊 就说一下什么算法策略"
我的内心:"??? 老师想我说啥…冷静分析"
老师:“这学期学过”
我:“动态规划!!!

 呼,终于回答完,嗯? 题目刚刚做到哪了。。。。。。

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

 对!拓扑排序!继续排!

 private static void tpSort() {
        int j = 0;//TODO
        ArrayDeque<Integer> q = new ArrayDeque<>();
        for (int i = 1; i <= vertexNum; ++i)
            if (inDegree[i] == 0)
                q.addLast(i);
        while (!q.isEmpty()) {
            int curr = q.pollFirst();
            nodeToOrder[curr] = ++j;
            for (Node node : nodes1[curr]) {
                int id = node.id;
                if (--inDegree[id] == 0)
                    q.addLast(id);
            }
        }
    }

排完。然后怎么做? 完了又没思路了…

 最短距离可以用 Dijkstra,但又怎么随着删除节点改变最小距离呢??
 删掉一个节点及这个节点所连的边后,要找到S到T的最短路径,一定要找到可以替代被删除点的一个或多个点.
&emsp考虑到图是 DAG ,拓扑排序后的图,删去一个节点后,若有顶点可以代替被删顶点V构成最小路径,那么一定有一条边从V的左边连接到 V 的右边(拓扑序下)。
即如图:
在这里插入图片描述
若删除节点V后,从S到T仍有一条最短路径的话,那么一定有一条边,其两个端点的拓扑序分别在V点的左边和右边(A节点和B节点)要解决问题我们只需要找到这样的一条最短的边即可。
怎么找到最短的边,一阵冥思苦想……

(此时老师讲到最小生成树) 生成树?? 嗯?? 生成树 !! 最小。。。   树。。  最小。。 线段树!
 没错,可以用线段树来储存这样的一条最小的边,这样搜索起来就方便很多!

那么总体的思路就来了:

1.先进行拓扑排序
2.然后对起点S和终点T分别用一次Dijkstra算法.(注意对终点T用dijkstra前,需要有一个反向的邻接表,因为图是有向图)
3.构造一颗线段树,储存拓扑序下节点到节点间的最小边
4.对于每次访问,若被删除节点原本就无法从起点到达或者无法从重点到达,则直接输出S到T的距离,否则,访问线段树,取得最小值
最小值为 d i s f r o m &ThickSpace; s t a r t [ x ] + w [ x , y ] + d i s f r o m &ThickSpace; e n d [ y ] ( w h e r e &ThickSpace; v &ThickSpace; i s &ThickSpace; b e t w e e n &ThickSpace; x &ThickSpace; a n d &ThickSpace; y ) di{s_{from\;start}}[x] + w[x,y] + di{s_{from\;end}}[y]\quad (where{\kern 1pt} \;v\;is\;between\;x\;and\;y) disfromstart[x]+w[x,y]+disfromend[y](wherevisbetweenxandy)

思路了,也下课了,下一节是计算机系统课.转移战场!继续战斗!

(此处省略一节课哒哒哒打代码和debug时间)

终于过了样例,尝试提交.震惊,得到的居然是WA
在这里插入图片描述
0.00%有点伤人…
于是就开始了无尽的修改…
但无论怎么找也找不到出错的地方。
放学了,心不在焉的吃饭又赶到了实验室,开始继续找错误
在这里插入图片描述
这一找,就是一个下午。。任然无果
计算机系统的题到是学了不少哈哈哈

此处特别鸣谢刘同学分享的美丽版Linux

找一个几个小时毫无进展的错误,确实令人恼火。我这一恼火吧,就想继续找bug

此处再次特别鸣谢刘同学多次尝试将我从坑中拉出来

然而我还是作死的继续找
此处先贴上WA代码

/*
 * Copyright (c) 2019 Ng Kimbing, HNU, All rights reserved. May not be used, modified, or copied without permission.
 * @Author: Ng Kimbing, HNU.
 * @LastModified:2019-04-24 T 09:55:36.973 +08:00
 */
package ACMProblems.General;

import java.io.*;
import java.util.*;

public class NowCoder_Delete {
    public static PrintWriter out = new PrintWriter(new BufferedOutputStream(System.out));
    static BufferedReader reader;
    static StringTokenizer tokenizer;

    public static void setStream(InputStream input) {
        reader = new BufferedReader(
                new InputStreamReader(input));
        tokenizer = new StringTokenizer("");
    }

    public static String next() throws IOException {
        while (!tokenizer.hasMoreTokens()) {
            tokenizer = new StringTokenizer(
                    reader.readLine());
        }
        return tokenizer.nextToken();
    }

    public static String readLine() throws IOException {
        return reader.readLine();
    }

    public static int nextInt() throws IOException {
        return Integer.parseInt(next());
    }

    public static char nextChar() throws IOException {
        return next().charAt(0);
    }

    public static double nextDouble() throws IOException {
        return Double.parseDouble(next());
    }

    private static long INF = 1L << 60;
    private static int vertexNum, edgeNum, s, t;

    static class Node {
        int id;
        long dis;

        public Node(int id, long dis) {
            this.id = id;
            this.dis = dis;
        }
    }

    private static Vector<Node>[] nodes1;
    private static Vector<Node>[] nodes2;
    private static long[] dis1;
    private static long[] dis2;
    private static long[] segmentTree;
    private static int[] inDegree;
    private static int[] nodeToOrder;

    private static void addEdge(int a, int b, int weight, Vector<Node>[] nodes) {
        nodes[a].add(new Node(b, weight));
    }

    private static int[] tpSort() {
        int[] a = new int[vertexNum + 1];
        int j = 0;//TODO
        ArrayDeque<Integer> q = new ArrayDeque<>();
        for (int i = 1; i <= vertexNum; ++i)
            if (inDegree[i] == 0)
                q.add(i);
        while (!q.isEmpty()) {
            int curr = q.pollFirst();
            a[curr] = ++j;
            for (Node node : nodes1[curr]) {
                int id = node.id;
                if (--inDegree[id] == 0)
                    q.add(id);
            }
        }
        return a;
    }

    static boolean[] visited;

    private static long[] dijkstra(int start, Vector<Node>[] nodes) {
        long[] dis = new long[vertexNum + 1];
        visited = new boolean[vertexNum + 1];
        Arrays.fill(dis, INF);
        dis[nodeToOrder[start]] = 0;
        PriorityQueue<Integer> q = new PriorityQueue<>(Comparator.comparingLong(o -> dis[nodeToOrder[o]]));
        q.add(start);
        while (!q.isEmpty()) {
            int curr = q.poll();
            if (visited[curr])
                continue;
            visited[curr] = true;
            for (Node node : nodes[curr]) {
                long d = node.dis;
                int id = node.id;
                long newDis = d + dis[nodeToOrder[curr]];
                if (newDis < dis[nodeToOrder[id]]) {
                    dis[nodeToOrder[id]] = newDis;
                    q.add(id);
                }
            }
        }
        return dis;
    }
//    private static long[] dijkstra(int start, Vector<Node>[] nodes) {
//        long[] dis = new long[vertexNum + 1];
//        Arrays.fill(dis, INF);
//        dis[start] = 0;
//        PriorityQueue<Integer> q = new PriorityQueue<>(Comparator.comparingLong(o -> dis[o]));
//        q.add(start);
//        while (!q.isEmpty()) {
//            int curr = q.poll();
//            for (Node node : nodes[curr]) {
//                long d = node.dis;
//                int id = node.id;
//                if (d + dis[curr] < dis[id]) {
//                    dis[id] = d + dis[curr];
//                    q.add(id);
//                }
//            }
//        }
//        return dis;
//    }

    static void updateTree(int currIndex, int currL, int currR, int left, int right, long weight) {
        if (left <= currL && right >= currR) {
            segmentTree[currIndex] = Math.min(segmentTree[currIndex], weight);
            return;
        }
        int mid = (currL + currR) >> 1;
        if (left <= mid)
            updateTree(currIndex << 1, currL, mid, left, right, weight);
        if (right > mid)
            updateTree(currIndex << 1 | 1, mid + 1, currR, left, right, weight);
    }

    static long ans;

    static void findMin(int midVertex) {
        ans = INF;
        findMin(1, midVertex, 1, vertexNum);
    }

    static void findMin(int currIndex, int midVertex, int currLeft, int currRight) {
        if (segmentTree[currIndex] < ans) {
            ans = segmentTree[currIndex];
        }
        if (currLeft == currRight)
            return; //一定要在上面那段的后面
        int mid = (currLeft + currRight) >> 1;
        if (midVertex <= mid)
            findMin(currIndex << 1, midVertex, currLeft, mid);
        else findMin(currIndex << 1 | 1, midVertex, mid + 1, currRight);
    }

    static void initialSegmentTree(int currPos, int left, int right) {
        segmentTree[currPos] = INF;
        if (left == right)
            return;
        int mid = (left + right) >> 1;
        initialSegmentTree(currPos << 1, left, mid);
        initialSegmentTree(currPos << 1 | 1, mid + 1, right);
    }

    static void buildSegmentTree() {
        for (int i = 1; i <= vertexNum; ++i) {
            for (Node node : nodes1[i]) {
                int from = i;
                int to = node.id;
                if (nodeToOrder[from] + 1 < nodeToOrder[to] &&
                        dis1[nodeToOrder[from]] < INF && dis2[nodeToOrder[to]] < INF)
                    updateTree(1, 1, vertexNum, nodeToOrder[from] + 1, nodeToOrder[to] - 1,
                            node.dis + dis1[nodeToOrder[from]] + dis2[nodeToOrder[to]]);//TODO
            }
        }
    }

    @SuppressWarnings("unchecked")
    public static void main(String[] args) throws Exception {
        setStream(System.in);
        vertexNum = nextInt();
        edgeNum = nextInt();
        s = nextInt();
        t = nextInt();
        nodes1 = new Vector[vertexNum + 1];
        nodes2 = new Vector[vertexNum + 1];
        segmentTree = new long[vertexNum << 2];
        inDegree = new int[vertexNum + 1];
        initialSegmentTree(1, 1, vertexNum);
        for (int i = 0; i < vertexNum + 1; ++i) {
            nodes1[i] = new Vector<>();
            nodes2[i] = new Vector<>();
        }
        for (int i = 0; i < edgeNum; ++i) {
            int from = nextInt();
            int to = nextInt();
            int weight = nextInt();
            ++inDegree[to];
            addEdge(from, to, weight, nodes1);
            addEdge(to, from, weight, nodes2);
        }
        nodeToOrder = tpSort();
        dis1 = dijkstra(s, nodes1);
        dis2 = dijkstra(t, nodes2);
        buildSegmentTree();
        int q = nextInt();
        while (q-- != 0) {
            int del = nextInt();
            if (dis1[nodeToOrder[del]] >= INF || dis2[nodeToOrder[del]] >= INF) {
                out.println(dis1[nodeToOrder[t]]);
                out.flush();
                continue;
            }
            findMin(nodeToOrder[del]);
            if (ans < INF)
                out.println(ans);
            else out.println(-1);
            out.flush();
        }
        out.flush();
//        out.println(Arrays.toString(dis1));
//        out.println(Arrays.toString(dis2));
//        out.flush();
    }
}

是在找不到问题,一气之下把代码改写成了C++。竟然得到了一个AC????????
在这里插入图片描述
C++ AC代码如下:

#include <iostream>
#include<vector>
#include<queue>

using namespace std;
static long long INF = 1LL << 60;
int vertexNum, edgeNum, s, t;

class Node {
    public:
        int id;
        long long dis;

        Node(int id, long long dis) {
            this->id = id;
            this->dis = dis;
        }

        bool operator<(const Node &b) const {
            return dis > b.dis;
        }
};

#define maxn 100005
vector<Node> nodes1[maxn];
vector<Node> nodes2[maxn];
long long dis1[maxn];
long long dis2[maxn];
long long segmentTree[maxn << 2];
int inDegree[maxn];
int nodeToOrder[maxn];

void addEdge(int a, int b, int weight, vector<Node> *nodes) {
    nodes[a].push_back(Node(b, weight));
}

void tpSort() {
    int j = 0;//TODO
    queue<int> q;
    for (int i = 1; i <= vertexNum; ++i)
        if (inDegree[i] == 0)
            q.push(i);
    while (!q.empty()) {
        int curr;
        curr = q.front();
        q.pop();
        nodeToOrder[curr] = ++j;
        for (Node node : nodes1[curr]) {
            int id = node.id;
            if (--inDegree[id] == 0)
                q.push(id);
        }
    }
}

void dijkstra(int start, vector<Node> *nodes, long long *dis) {
    priority_queue<Node> q;
    bool vis[vertexNum + 1];
    for (int i = 1; i <= vertexNum; ++i) dis[i] = INF, vis[i] = 0;
    q.push((Node) {start, 0});
    dis[start] = 0;
    while (!q.empty()) {
        int u = q.top().id;
        q.pop();
        if (vis[u])
            continue;
        vis[u] = 1;
        for (auto p : nodes[u])
            if (dis[u] + p.dis < dis[p.id]) {
                dis[p.id] = dis[u] + p.dis;
                q.push((Node{p.id, dis[p.id]}));
            }
    }
}

long min(long a, long b) {
    return a > b ? b : a;
}

static void updateTree(int currIndex, int currL, int currR, int left, int right, long long weight) {
    if (left <= currL && right >= currR) {
        segmentTree[currIndex] = min(segmentTree[currIndex], weight);
        return;
    }
    int mid = (currL + currR) >> 1;
    if (left <= mid)
        updateTree(currIndex << 1, currL, mid, left, right, weight);
    if (right > mid)
        updateTree(currIndex << 1 | 1, mid + 1, currR, left, right, weight);
}

long long ans;

void findMin(int currIndex, int midVertex, int currLeft, int currRight) {
    if (segmentTree[currIndex] < ans) {
        ans = segmentTree[currIndex];
    }
    if (currLeft == currRight)
        return; //一定要在上面那段的后面
    int mid = (currLeft + currRight) >> 1;
    if (midVertex <= mid)
        findMin(currIndex << 1, midVertex, currLeft, mid);
    else findMin(currIndex << 1 | 1, midVertex, mid + 1, currRight);
}

static void findMin(int midVertex) {
    ans = INF;
    findMin(1, midVertex, 1, vertexNum);
}

static void initialSegmentTree(int currPos, int left, int right) {
    segmentTree[currPos] = INF;
    if (left == right)
        return;
    int mid = (left + right) >> 1;
    initialSegmentTree(currPos << 1, left, mid);
    initialSegmentTree(currPos << 1 | 1, mid + 1, right);
}

static void buildSegmentTree() {
    for (int i = 1; i <= vertexNum; ++i) {
        for (Node node : nodes1[i]) {
            int from = i;
            int to = node.id;
            if (nodeToOrder[from] + 1 < nodeToOrder[to] &&
                dis1[from] < INF && dis2[to] < INF)
                updateTree(1, 1, vertexNum, nodeToOrder[from] + 1, nodeToOrder[to] - 1,
                           node.dis + dis1[from] + dis2[to]);//TODO
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> vertexNum >> edgeNum >> s >> t;
    initialSegmentTree(1, 1, vertexNum);
    for (int i = 0; i < vertexNum + 1; ++i) {
        nodes1[i].clear();
        nodes2[i].clear();
    }
    for (int i = 0; i < edgeNum; ++i) {
        int from, to, weight;
        cin >> from >> to >> weight;
        ++inDegree[to];
        addEdge(from, to, weight, nodes1);
        addEdge(to, from, weight, nodes2);
    }
    tpSort();
    dijkstra(s, nodes1, dis1);
    dijkstra(t, nodes2, dis2);
    buildSegmentTree();
    int q;
    cin >> q;
    while (q-- != 0) {
        int del;
        cin >> del;
        if (dis1[del] >= INF || dis2[del] >= INF) {
            cout << dis1[t] << "\n";
            continue;
        }
        findMin(nodeToOrder[del]);
        if (ans < INF)
            cout << ans << "\n";
        else cout << -1 << "\n";
    }
//    cout << endl;
//        out.println(Arrays.toString(dis1));
//        out.println(Arrays.toString(dis2));
//        out.flush();
}

为什么!!??为什么!!?我fong了

接下来又是N长时间的找bug,甚至将其与改写之后的C++代码地毯式比对,依然无果,就是一个AC,一个WA。。。。
复习的声音在我耳旁回响。可是我还是很想解决这个问题,因为这已经不是第一次C++能AC而Java不能 或者JAVA AC了C++不能。。。。
经过苦战到晚上,终于发现了问题所在
问题的关键就在于Dijkstra算法中的优先队列的定义.

PriorityQueue<Integer> q = new PriorityQueue<>(Comparator.comparingLong(o -> dis[o]));

(我正尝试通过访问数组来比较优先队列中的元素的大小)
将其改为如下代码后就顺利AC

PriorityQueue<Node> q = new PriorityQueue<>(Comparator.comparingLong(o -> o.dis));

实验测试:

        int dis[] = {8,3,5,5,9};
        PriorityQueue<Integer> q = new PriorityQueue<>(Comparator.comparingInt(o -> dis[o]));
        q.add(4);
        q.add(0);
        System.out.println(q.poll());
        System.out.println(q.poll());
        System.out.println(q.poll());

以上代码会输出0 4 null

而若将代码修改成

        int dis[] = {8,3,5,5,9};
        PriorityQueue<Integer> q = new PriorityQueue<>(Comparator.comparingInt(o -> dis[o]));
        q.add(4);
        q.add(0);
        dis[4] = 0;
        q.add(4);
        System.out.println(q.poll());
        System.out.println(q.poll());
        System.out.println(q.poll());

将数组的值修改后再一次add,可能会改变原来优先队列中的顺序.这样可能也就会带来意想不到的错误了。
以后写dijkstra还是老老实实用node来填泛型吧。。。。血的教训。。。

最后附上AC 的Java代码:

import java.io.*;
import java.util.*;
 
public class Main {
    public static PrintWriter out = new PrintWriter(new BufferedOutputStream(System.out));
    static BufferedReader reader;
    static StringTokenizer tokenizer;
 
    public static void setStream(InputStream input) {
        reader = new BufferedReader(
                new InputStreamReader(input));
        tokenizer = new StringTokenizer("");
    }
 
    public static String next() throws IOException {
        while (!tokenizer.hasMoreTokens()) {
            tokenizer = new StringTokenizer(
                    reader.readLine());
        }
        return tokenizer.nextToken();
    }
 
    public static String readLine() throws IOException {
        return reader.readLine();
    }
 
    public static int nextInt() throws IOException {
        return Integer.parseInt(next());
    }
 
    public static char nextChar() throws IOException {
        return next().charAt(0);
    }
 
    public static double nextDouble() throws IOException {
        return Double.parseDouble(next());
    }
 
    static int maxn = 100005;
    private static long INF = 1L << 60;
    private static int vertexNum, edgeNum, s, t;
 
    static class Node {
        int id;
        long dis;
 
        public Node(int id, long dis) {
            this.id = id;
            this.dis = dis;
        }
    }
 
    private static Vector<Node>[] nodes1;
    private static Vector<Node>[] nodes2;
    private static long[] dis1;
    private static long[] dis2;
    private static long[] segmentTree;
    private static int[] inDegree;
    private static int[] nodeToOrder = new int[maxn + 1];
    ;
 
    private static void addEdge(int a, int b, int weight, Vector<Node>[] nodes) {
        nodes[a].add(new Node(b, weight));
    }
 
    private static void tpSort() {
        int j = 0;//TODO
        ArrayDeque<Integer> q = new ArrayDeque<>();
        for (int i = 1; i <= vertexNum; ++i)
            if (inDegree[i] == 0)
                q.addLast(i);
        while (!q.isEmpty()) {
            int curr = q.pollFirst();
            nodeToOrder[curr] = ++j;
            for (Node node : nodes1[curr]) {
                int id = node.id;
                if (--inDegree[id] == 0)
                    q.addLast(id);
            }
        }
    }
//    private static long[] dijkstra(int start, Vector<Node>[] nodes) {
//        long[] dis = new long[vertexNum + 1];
//        boolean[] visited = new boolean[vertexNum + 1];
//        Arrays.fill(dis, INF);
//        dis[start] = 0;
//        PriorityQueue<Integer> q = new PriorityQueue<>(Comparator.comparingLong(o -> dis[o]));
//        q.add(start);
//        while (!q.isEmpty()) {
//            int curr = q.poll();
//            if (visited[curr])
//                continue;
//            visited[curr] = true;
//            for (Node node : nodes[curr]) {
//                long d = node.dis;
//                int id = node.id;
//                if (d + dis[curr] < dis[id]) {
//                    dis[id] = d + dis[curr];
//                    q.add(id);
//                }
//            }
//        }
//        return dis;
//    }
 
    static long[] dijkstra(int start, Vector<Node>[] nodes) {
        long[] dis = new long[vertexNum + 1];
        PriorityQueue<Node> q = new PriorityQueue<>(Comparator.comparingLong(o -> o.dis));
        boolean vis[] = new boolean[vertexNum + 1];
        for (int i = 1; i <= vertexNum; ++i) {
            dis[i] = INF;
            vis[i] = false;
        }
        dis[start] = 0;
        q.add(new Node(start, 0));
        while (!q.isEmpty()) {
            int u = q.poll().id;
            if (vis[u])
                continue;
            vis[u] = true;
            for (Node p : nodes[u])
                if (dis[u] + p.dis < dis[p.id]) {
                    dis[p.id] = dis[u] + p.dis;
                    q.add(new Node(p.id, dis[p.id]));
                }
        }
        return dis;
    }
 
    static void updateTree(int currIndex, int currL, int currR, int left, int right, long weight) {
        if (left <= currL && right >= currR) {
            segmentTree[currIndex] = Math.min(segmentTree[currIndex], weight);
            return;
        }
        int mid = (currL + currR) >> 1;
        if (left <= mid)
            updateTree(currIndex << 1, currL, mid, left, right, weight);
        if (right > mid)
            updateTree(currIndex << 1 | 1, mid + 1, currR, left, right, weight);
    }
 
    static long ans;
 
    static void findMin(int midVertex) {
        ans = INF;
        findMin(1, midVertex, 1, vertexNum);
    }
 
    static void findMin(int currIndex, int midVertex, int currLeft, int currRight) {
        if (segmentTree[currIndex] < ans) {
            ans = segmentTree[currIndex];
        }
        if (currLeft == currRight)
            return; //一定要在上面那段的后面
        int mid = (currLeft + currRight) >> 1;
        if (midVertex <= mid)
            findMin(currIndex << 1, midVertex, currLeft, mid);
        else findMin(currIndex << 1 | 1, midVertex, mid + 1, currRight);
    }
 
    static void initialSegmentTree(int currPos, int left, int right) {
        segmentTree[currPos] = INF;
        if (left == right)
            return;
        int mid = (left + right) >> 1;
        initialSegmentTree(currPos << 1, left, mid);
        initialSegmentTree(currPos << 1 | 1, mid + 1, right);
    }
 
    static void buildSegmentTree() {
        for (int i = 1; i <= vertexNum; ++i) {
            for (Node node : nodes1[i]) {
                int from = i;
                int to = node.id;
                if (nodeToOrder[from] + 1 < nodeToOrder[to] &&
                        dis1[from] < INF && dis2[to] < INF)
                    updateTree(1, 1, vertexNum, nodeToOrder[from] + 1, nodeToOrder[to] - 1,
                            node.dis + dis1[from] + dis2[to]);//TODO
            }
        }
    }
 
    @SuppressWarnings("unchecked")
    public static void main(String[] args) throws Exception {
        setStream(System.in);
        vertexNum = nextInt();
        edgeNum = nextInt();
        s = nextInt();
        t = nextInt();
        nodes1 = new Vector[maxn + 1];
        nodes2 = new Vector[maxn + 1];
        segmentTree = new long[maxn << 2];
        inDegree = new int[maxn + 1];
        initialSegmentTree(1, 1, vertexNum);
        for (int i = 0; i < vertexNum + 1; ++i) {
            nodes1[i] = new Vector<>();
            nodes1[i].clear();
            nodes2[i] = new Vector<>();
            nodes2[i].clear();
        }
        for (int i = 0; i < edgeNum; ++i) {
            int from = nextInt();
            int to = nextInt();
            int weight = nextInt();
            ++inDegree[to];
            addEdge(from, to, weight, nodes1);
            addEdge(to, from, weight, nodes2);
        }
        tpSort();
        dis1 = dijkstra(s, nodes1);
        dis2 = dijkstra(t, nodes2);
        buildSegmentTree();
        int q = nextInt();
        while (q-- != 0) {
            int del = nextInt();
            if (dis1[del] >= INF || dis2[del] >= INF) {
                out.println(dis1[t]);
//                out.flush();
                continue;
            }
            findMin(nodeToOrder[del]);
            if (ans < INF)
                out.println(ans);
            else out.println(-1);
            if (q % 1000 == 0)
                out.flush();
        }
//        out.println(Arrays.toString(dis1));
//        out.println(Arrays.toString(dis2));
//        out.flush();
    }
}

终于可以复习”校史”计算机系统了。。。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值