[洛谷P5340][TJOI2019]大中锋的游乐场

题目大意:有$n(n\leqslant10^4)$个点,$m(m\leqslant10^5)$条边的无向图,每个点有一个属性$A/B$,要求$|cnt_A-cnt_B|\leqslant k(k\leqslant10)$,问$S\to T$最短路径

题解:把每个点拆成$2k+1$个点,分别标号为$[-k,k]$,表示到这$cnt_A-cnt_B$的值,跑最短路即可。

卡点:各种地方没有把$n$改成$n(2k+1)$

 

C++ Code:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#define maxn (10010 * 21)
#define maxm (100010 * 21)

int head[maxn], cnt;
struct Edge {
	int to, nxt, w;
} e[maxm << 1];
inline void addedge(int a, int b, int c) {
	e[++cnt] = (Edge) { b, head[a], c }; head[a] = cnt;
}

int n, m, k, K, S, T;

namespace Graph {
	int V[maxn << 2];
	long long dis[maxn];
	inline int getmin(int a, int b) { return dis[a] < dis[b] ? a : b; }

	void modify(int rt, int l, int r, int p, int num) {
		if (l == r) {
			V[rt] = num;
			return ;
		}
		const int mid = l + r >> 1;
		if (p <= mid) modify(rt << 1, l, mid, p, num);
		else modify(rt << 1 | 1, mid + 1, r, p, num);
		V[rt] = getmin(V[rt << 1], V[rt << 1 | 1]);
	}
	long long dijkstra(int S, int T) {
		const int N = n * K + 1;
		memset(dis, 0x3f, sizeof dis);
		memset(V, 0, sizeof V);
		dis[S] = 0, modify(1, 1, N, S, S);
		for (int TIM = n * K + 1; TIM; --TIM) {
			int u = V[1];
			modify(1, 1, N, u, 0);
			for (int i = head[u]; i; i = e[i].nxt) {
				int v = e[i].to;
				if (dis[v] > dis[u] + e[i].w) {
					dis[v] = dis[u] + e[i].w;
					modify(1, 1, N, v, v);
				}
			}
		}
		return dis[T];
	}
}

int TIM, w[maxn];
int main() {
	std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
	std::cin >> TIM;
	while (TIM --> 0) {
		std::cin >> n >> m >> k;
		K = 2 * k + 1;
		for (int i = 1, x; i <= n; ++i) std::cin >> x, w[i] = x - 1;
		for (int i = 0, a, b, c; i < m; ++i) {
			std::cin >> a >> b >> c;
			--a, --b;
			for (int j = 2; j <= K; ++j) {
				if (w[b + 1]) addedge(a * K + j - 1, b * K + j, c);
				else addedge(a * K + j, b * K + j - 1, c);
				if (w[a + 1]) addedge(b * K + j - 1, a * K + j, c);
				else addedge(b * K + j, a * K + j - 1, c);
			}
		}
		std::cin >> S >> T;
		--S, --T;
		for (int j = 1; j <= K; ++j) addedge(T * K + j, n * K + 1, 0);
		int St = S * K + k + 1;
		if (w[S + 1]) ++St; else --St;
		long long ans = Graph::dijkstra(St, n * K + 1);
		std::cout << (ans == 0x3f3f3f3f3f3f3f3f ? -1 : ans) << '\n';
		if (TIM) {
			memset(head, 0, sizeof head);
			cnt = 0;
		}
	}
	return 0;
}

  

posted @ 2019-06-27 16:22  Memory_of_winter  阅读(183)  评论(0编辑  收藏  举报