제출 #79475

#제출 시각아이디문제언어결과실행 시간메모리
79475JustInCaseEvacuation plan (IZhO18_plan)C++17
100 / 100
712 ms73968 KiB
#include <bits/stdc++.h>

const int32_t MAX_N = 1e5;
const int32_t LOG_MAX_N = 17;
const int32_t MAX_M = 5e5;
const int32_t INF = 2e9;

class Graph {
private:
	struct Node {
		bool isVisited;
		int32_t id, dist;
		std::vector< int32_t > v;
	
		Node() {
			dist = INF;
		}
	};

	struct Edge {
		int32_t w;
		Node *u, *v;

		Node* Get(Node *x) const {
			if(u == x) {
				return v;
			}
			else {
				return u;
			}
		}
	};

public:
	int32_t cntNodes, cntEdges;
	Node nodes[MAX_N + 5];
	Edge edges[MAX_M + 5];

	void Init(int32_t _cntNodes, int32_t _cntEdges) {
		cntNodes = _cntNodes;
		cntEdges = _cntEdges;
	
		for(int32_t i = 1; i <= _cntNodes; i++) {
			nodes[i].id = i;
		}
	}
		
	void AddEdge(Node *u, Node *v, int32_t w, int32_t ind) {
		u->v.push_back(ind);
		v->v.push_back(ind);

		edges[ind] = { w, u, v };
	}
	
	friend bool operator< (const std::pair< int32_t, Node* > &x, const std::pair< int32_t, Node* > &y) {
		return x.first > y.first;
	}

	void Dijkstra(const std::vector< int32_t > &st) {
		std::priority_queue< std::pair< int32_t, Node* > > pq;

		for(auto &x : st) {
			nodes[x].dist = 0;
			pq.push({ 0, &nodes[x] });
		}

		while(!pq.empty()) {
			Node *curr = pq.top().second;
			pq.pop();

			if(curr->isVisited) {
				continue;
			}
			curr->isVisited = true;

			for(auto &x : curr->v) {
				Node *nxtNode = edges[x].Get(curr);
				if(!nxtNode->isVisited && nxtNode->dist > curr->dist + edges[x].w) {
					nxtNode->dist = curr->dist + edges[x].w;
					pq.push({ nxtNode->dist, nxtNode });
				}
			}
		}
	}
};

struct Edge {
	int32_t u, v, minDist;

	bool operator< (const Edge &other) const {
		return minDist > other.minDist;
	}
};

Graph g;
Edge edges[MAX_M + 5];

class DSU {
private:
	int32_t parent[MAX_N + 5], siz[MAX_N + 5];

public:
	void Init(int32_t _cntNodes) {
		for(int32_t i = 1; i <= _cntNodes; i++) {
			parent[i] = i;
			siz[i] = 1;
		}
	}

	int32_t Find(int32_t x) {
		if(parent[x] == x) {
			return x;
		}
		else {
			parent[x] = Find(parent[x]);
			return parent[x];
		}
	}

	void Unite(int32_t x, int32_t y) {
		if(siz[x] > siz[y]) {
			parent[y] = x;
		}
		else if(siz[x] < siz[y]) {
			parent[x] = y;
		}
		else {
			parent[y] = x;
			siz[x] += siz[y];
		}
	}
};

DSU dsu;

class Tree {
private:
	struct Node {
		bool isVisited;
		int32_t id, inTime, outTime;
		std::pair< Node*, int32_t > ancs[LOG_MAX_N + 5];
		std::vector< std::pair< Node*, int32_t > > v;
	
		bool IsAncOf(Node *x) const {
			if(inTime <= x->inTime && outTime >= x->outTime) {
				return true;
			}
			
			return false;
		}
	};

public:
	int32_t cntNodes;
	Node nodes[MAX_N + 5];

	void Init(int32_t _cntNodes) {
		cntNodes = _cntNodes;

		for(int32_t i = 1; i <= _cntNodes; i++) {
			nodes[i].id = i;
			
			for(int32_t j = 0; j < LOG_MAX_N; j++) {
				nodes[i].ancs[j] = { nullptr, 0 };
			}
		}
	}

	void AddEdge(Node *u, Node *v, int32_t w) {
		u->v.push_back({ v, w });
		v->v.push_back({ u, w });
	}

	void PrecomputeDfs(Node *nd, int32_t &dfsTime) {
		nd->isVisited = true;
		nd->inTime = dfsTime++;

		for(auto &x : nd->v) {
			if(!x.first->isVisited) {
				PrecomputeDfs(x.first, dfsTime);
			}
			else {
				nd->ancs[0] = { x.first, x.second };
			}
		}

		nd->outTime = dfsTime - 1;
	}

	void PrecomputeAncs() {
		for(int32_t j = 1; j < LOG_MAX_N; j++) {
			for(int32_t i = 1; i <= cntNodes; i++) {
				if(nodes[i].ancs[j - 1].first != nullptr) {
					nodes[i].ancs[j] = { 
						nodes[i].ancs[j - 1].first->ancs[j - 1].first,
						std::min(nodes[i].ancs[j - 1].second, nodes[i].ancs[j - 1].first->ancs[j - 1].second)
					};
				}
			}
		}
	}

	int32_t GetMinDistBetween(Node *u, Node *v) {
		int32_t ans = INF;
		
		for(int32_t i = LOG_MAX_N - 1; i >= 0; i--) {
			if(u->ancs[i].first != nullptr && !u->ancs[i].first->IsAncOf(v)) {
				ans = std::min(ans, u->ancs[i].second);
				u = u->ancs[i].first;
			}
		}

		for(int32_t i = LOG_MAX_N - 1; i >= 0; i--) {
			if(v->ancs[i].first != nullptr && !v->ancs[i].first->IsAncOf(u)) {
				ans = std::min(ans, v->ancs[i].second);
				v = v->ancs[i].first;
			}
		}

		if(!u->IsAncOf(v)) {
			ans = std::min(ans, u->ancs[0].second);
		}
		if(!v->IsAncOf(u)) {
			ans = std::min(ans, v->ancs[0].second);
		}

		return ans;
	}
};

Tree t;

int main() {
	std::ios_base::sync_with_stdio(false);
	std::cin.tie(nullptr);

	int32_t n, m;
	std::cin >> n >> m;

	g.Init(n, m);

	for(int32_t i = 0; i < m; i++) {
		int32_t u, v, w;
		std::cin >> u >> v >> w;
		
		g.AddEdge(&g.nodes[u], &g.nodes[v], w, i);
	}

	int32_t k;
	std::cin >> k;

	std::vector< int32_t > special(k); 
	for(int32_t i = 0; i < k; i++) {
		std::cin >> special[i];
	}

	g.Dijkstra(special);

	for(int32_t i = 0; i < m; i++) {
		edges[i] = { g.edges[i].u->id, g.edges[i].v->id, std::min(g.edges[i].u->dist, g.edges[i].v->dist) };
	}

	std::sort(edges, edges + m);
	
	dsu.Init(n);
	t.Init(n);
	for(int32_t i = 0; i < m; i++) {
		int32_t parU = dsu.Find(edges[i].u);
		int32_t parV = dsu.Find(edges[i].v);

		if(parU != parV) {
			dsu.Unite(parU, parV);
			t.AddEdge(&t.nodes[edges[i].u], &t.nodes[edges[i].v], edges[i].minDist);
		}
	}

	int32_t dfsTime = 0;
	t.PrecomputeDfs(&t.nodes[1], dfsTime);

	t.PrecomputeAncs();

	int32_t q;
	std::cin >> q;

	for(int32_t i = 0; i < q; i++) {
		int32_t u, v;
		std::cin >> u >> v;

		std::cout << t.GetMinDistBetween(&t.nodes[u], &t.nodes[v]) << '\n';
	}
}

#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...