社区讨论

5分 不知道思路哪有问题 求hack

P13823「Diligent-OI R2 C」所谓伊人参与者 1已保存回复 1

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
1 条
当前快照
1 份
快照标识符
@mhjd7ube
此快照首次捕获于
2025/11/04 00:39
4 个月前
此快照最后确认于
2025/11/04 00:39
4 个月前
查看原帖
本题我的思路是
Step0:给题目中每一条边建一条反向边,题目中边颜色为0,增加的反向边颜色为1,将0的边存为一张图,1的边存为另一张图
Step1:首先bfs划分出整个图有多少个连通块,并记录每个连通块内最大的数所在的位置(可能有多个)
Step2:对每个连通块,一开始把所有最大的数的位置的ans置为0,并加入队列,每次取出队头,用队头更新周边的点,如果这一步边的颜色与上一步的颜色不一样,则ans[new]=ans[x]+1,如果一样则ans[new]=ans[x],并把更新后的点和边的颜色加入队列
虽然代码实现之后严格上是TLE的,但是为什么前面2-5的Subtask都会WA呢?是思路哪里有问题吗?
整体代码如下:
CPP
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <iomanip>
#define N 500010

using namespace std;
int n, m, p[N], head[2][N], ver[2][N], nxt[2][N], tot[2]; // 邻接表建边[2]代表边颜色
int circ, v[N], ans[N];  // 连通块个数,Visit[],答案
queue<int> Maxst[N];  // 记录每个连通块内数值最大点的编号

long long read() {
	long long x = 0, h = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		if (ch == '-')
			h = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = x * 10 + (long long)(ch - '0');
		ch = getchar();
	}
	return x * h;
}

void add(int x, int y, int tp) { // (出发点,到达点,边的颜色)
	ver[tp][++tot[tp]] = y;
	nxt[tp][tot[tp]] = head[tp][x];
	head[tp][x] = tot[tp];
}

void get_circle(int st, int id) {  // 通过起始点找到此连通块所有点
	queue<int> q;
	while (!q.empty())
		q.pop();
	int maxx = p[st];
	Maxst[id].push(st);
	q.push(st);
	v[st] = 1;
	while (!q.empty()) {
		int x = q.front();
		q.pop();
		for (int k = 0; k <= 1; k++) {
			for (int i = head[k][x]; i; i = nxt[k][i]) {
				int y = ver[k][i];
				if (v[y])
					continue;

				// label y
				v[y] = 1;
				// queue
				q.push(y);
				// Maxst
				if (p[y] > maxx) {
					while (!Maxst[id].empty())
						Maxst[id].pop();
					Maxst[id].push(y);
				} else if (p[y] == maxx)
					Maxst[id].push(y);
			}
		}
	}
}

void get_ans(int id) {  // 通过bfs更新一个连通块内所有的答案
	queue<pair<int, int> > q;
	while (!q.empty())
		q.pop();
	while (!Maxst[id].empty()) {
		int x = Maxst[id].front();
		Maxst[id].pop();
		ans[x] = 0;  // 最大值处答案为0
		q.push(make_pair(x, 2));  // 从最大点出发到任何点需要交换一次,所以颜色是特殊的2,保证第一次更新与颜色不一样
	}
	while (!q.empty()) {
		int x = q.front().first;
		int ltp = q.front().second;
		q.pop();
		for (int k = 0; k <= 1; k++) {   // 枚举不同颜色的边
			for (int i = head[k][x]; i; i = nxt[k][i]) {
				int y = ver[k][i];
				if (y == x)
					continue;
				if (ans[y] > ans[x] + (k != ltp)) {   // 判断更新条件
					ans[y] = ans[x] + (int)(k != ltp);
					q.push(make_pair(y, k));
				}
			}
		}
	}
}

int main() {
	n = read();
	m = read();
	for (int i = 1; i <= n; i++)
		p[i] = read(), ans[i] = 99999999;

	for (int i = 1; i <= m; i++) {
		int u = read();
		int v = read();
		if (u == v)
			continue;
		add(u, v, 0);  // 题目中的图
		add(v, u, 1);  // 建立的所有边反向的图
	}
	while (1) {
		int st = 0;
		for (int i = 1; i <= n; i++) {
			if (!v[i]) {
				st = i;
				break;
			}
		}
		if (!st)   // 是否有没被统计的连通块
			break;
		circ++;  // 记录环数
		get_circle(st, circ);  // 统计连通块
	}
	for (int i = 1; i <= circ; i++) // 分别计算每个连通块的答案
		get_ans(i);
	for (int i = 1; i <= n; i++) {
		printf("%d ", ans[i]);
	}
	return 0;
}

回复

1 条回复,欢迎继续交流。

正在加载回复...