hdu 5361 In Touch(最短路+并查集)

题目链接:hdu 5361 In Touch


最短路,D[i]表示从i节点出发时最短距离,最后答案减掉C[i]即可。然后用并查集优化维护处理过的节点。


#pragma comment(linker, "/STACK:102400000,102400000")
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>

using namespace std;
typedef long long ll;
const int maxn = 2 * 1e5 + 5;
const ll inf = 1LL << 60;

struct Pi {
	int pos;
	ll dis;
	Pi (int pos = 0, ll dis = 0): pos(pos), dis(dis) {}
	bool operator < (const Pi& u) const {
		return dis > u.dis;
	}
};

int N, L[maxn], R[maxn], C[maxn], F[maxn];
ll D[maxn];

int find (int x) {
	return F[x] = (F[x] == x ? x : find(F[x]));
}

void init () {
	scanf("%d", &N);
	for (int i = 1; i <= N; i++) {
		F[i] = i;
		D[i] = inf;
	}
	for (int i = 1; i <= N; i++)
		scanf("%d", &L[i]);
	for (int i = 1; i <= N; i++)
		scanf("%d", &R[i]);
	for (int i = 1; i <= N; i++)
		scanf("%d", &C[i]);
}

void solve (int s) {
	D[s] = C[s];
	priority_queue<Pi> Q;
	Q.push(Pi(s, D[s]));

	while (!Q.empty()) {
		int u = Q.top().pos;
		Q.pop();

		for (int i = -1; i <= 1; i += 2) {
			int lp = u + L[u] * i;
			int rp = u + R[u] * i;
			if (lp > rp)
				swap(lp, rp);

			lp = max(lp, 1);
			lp = min(lp, N + 1);

			if (lp > rp)
				continue;

			while (true) {
				lp = find(lp);
				if (lp <= 0 || lp > N || lp > rp)
					break;
				if (D[lp] > D[u] + C[lp]) {
					D[lp] = D[u] + C[lp];
					Q.push(Pi(lp, D[lp]));
				}
				F[find(lp)] = find(lp + 1);
				lp++;
			}
		}
	}

	printf("0");
	for (int i = 2; i <= N; i++)
		printf(" %I64d", D[i] == inf ? -1 : D[i] - C[i]);
	printf("\n");
}

int main () {
	int cas;
	scanf("%d", &cas);
	while (cas--) {
		init();
		solve(1);
	}
	return 0;
}


你可能感兴趣的:(hdu 5361 In Touch(最短路+并查集))