SPOJ4882题解

由于SPOJ的服务器过于优异,暴力也给过了。
STL真是个好东西。

主要思路:求出一个点能到达的点集,然后把点集的各个点权值加起来

  1. 使用STL的bitset记录能到达的点集
  2. 拓扑排序得到拓扑序列,倒序遍历拓扑序列,更新能到达的点集
#include <cstring>
#include <cstdio>
#include <bitset>

using namespace std;

const int maxn = 20003;
const int maxen = 500003;

int n, m, val[maxn];
int in[maxn], qn, que[maxn];
int head[maxn], las[maxen], to[maxen];

bitset <20003> have[maxn];

void topo() {
	qn = 0;
	for (int i = 1; i <= n; i++)
		if (! in[i]) que[++qn] = i;
	for (int i = 1, u, v; i <= qn; i++) {
		u = que[i];
		for (int j = head[u]; j; j = las[j]) {
			v = to[j]; in[v]--;
			if (! in[v]) que[++qn] = v;
		}
	}
}
void solve() {
	for (int i = qn, u, v; i >= 1; i--) {
		u = que[i];
		for (int j = head[u]; j; j = las[j]) {
			v = to[j];
			have[u] |= have[v];
		}
	}
	for (int i = 1, ans; i <= n; i++) {
		ans = 0;
		for (int j = 1; j <= n; j++)
			if (have[i][j]) ans += val[j];
		printf("%d ", ans);
		have[i].reset();
	}
	printf("\n");
}

int main() {
	int T; scanf("%d", &T);
	while (T--) {
		scanf("%d%d", &n, &m);
		for (int i = 1; i <= n; i++) {
			scanf("%d", &val[i]);
			have[i][i] = 1;
		}
		
		memset(head, 0, sizeof(head));
		for (int i = 1, u, v; i <= m; i++) {
			scanf("%d%d", &u, &v);
			to[i] = v; las[i] = head[u]; head[u] = i;
			in[v]++;
		}
		
		topo();
		solve();
	}
	
	return 0;
}
posted @ 2020-04-28 09:07  northpoleforce  阅读(108)  评论(0)    收藏  举报