CF1515G Phoenix and Odometers 题解

CF1515G Phoenix and Odometers 题解

首先起点终点为同一个点告诉我们实际上合法的路径只在自己所属的强连通分量内。考虑到要求的实际上是模意义下的和,那么考虑把路径环拆成多个环。由裴蜀定理可以知道的是有一组 \(x\) 满足 \(a_1x_1+a_2x_2+\cdots+a_nx_n=\gcd(a1,a2,\cdots,a_n)\),那么我们只要求出多个环的 \(\gcd\) 就可以求出答案了。这里需要说明的是如果环之间不相交,无法通达又怎么处理?事实上只需要将通过路径上的环走 \(t\) 次就可以消除影响。

现在考虑的是解决求环的 \(\gcd\)。我们显然无法求出每个环,考虑去求一些简单环再去转化。我们先建出一棵有向 dfs 树,于是定义简单环为只有一条非树边的环。手模一下可以发现非简单环与其中包含的一个简单环的 \(\gcd\) 和这个非简单环中包含的两个简单环的 \(\gcd\) 相等,本质上只是去除了一个公共部分,推广一下就会发现只需要算简单环。那么对于非树边 \(a\to b\),环的权值就是 \(sum_a+w(a,b)-sum_b\),然后就做完了。

代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 5;
int n, m, T;
struct Node {
	int to, nxt, id, w;
} e[N];
struct node {
	int x, y, id, w;
} ve[N];
int head[N], bnt;
void add(int u, int v, int id, int w) {
	e[++bnt] = {v, head[u], id, w};
	head[u] = bnt;
}

int dfn[N], low[N], tim;
int stk[N], top;
bool ins[N];
int bel[N], cnt;
vector<int>scc[N];
void Tarjan(int x) {
	dfn[x] = low[x] = ++tim;
	stk[++top] = x;
	ins[x] = 1;
	for (int i = head[x]; i; i = e[i].nxt) {
		int y = e[i].to;
		if (!dfn[y]) {
			Tarjan(y);
			low[x] = min(low[x], low[y]);
		}
		else if (ins[y]) low[x] = min(low[x], dfn[y]);
	}
	if (low[x] == dfn[x]) {
		int y;
		++cnt;
		do {
			y = stk[top--];
			bel[y] = cnt;
			ins[y] = 0;
			scc[cnt].push_back(y);
		} while (x != y);
	}
}
int g[N];
vector<pair<int, int>>v[N];
bool vis[N];
vector<int>vc;
int cp;
void build(int x) {
	vis[x] = 1;
	for (int i = head[x]; i; i = e[i].nxt) {
		int y = e[i].to;
		if (!ins[y]) continue;
		if (vis[y]) vc.push_back(e[i].id);
		else v[x].emplace_back(y, e[i].w), build(y), ++cp;
	}
} 
int sm[N];
void dfs(int x, int fa) {
	for (auto p : v[x]) {
		int y = p.first;
		if (y == fa) continue;
		sm[y] = sm[x] + p.second;
		dfs(y, x);
	}
}
void sve(int s) {
	cp = 0;
	for (int i : scc[s]) ins[i] = 1;
	vc.clear();
	build(scc[s][0]);
	dfs(scc[s][0], 0);
	for (int i : vc) {
		int x = ve[i].x, y = ve[i].y;
		g[s] = __gcd(g[s], sm[x] - sm[y] + ve[i].w);
	}
	for (int i : scc[s]) ins[i] = 0;
}
	
signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n >> m;
	for (int i = 1; i <= m; i++) {
		int x, y, v;
		cin >> x >> y >> v;
		ve[i] = {x, y, i, v};
		add(x, y, i, v);
	}
	for (int i = 1; i <= n; i++)
		if (!dfn[i]) Tarjan(i);
	for (int i = 1; i <= cnt; i++)
		sve(i);
	cin >> T;
	while (T--) {
		int v, s, t;
		cin >> v >> s >> t;
		if (s % t != 0 && !g[bel[v]]) cout << "NO\n";
		else if ((t - s) % __gcd(g[bel[v]], t) == 0) cout << "YES\n";
		else cout << "NO\n";
	}
	return 0;
}
posted @ 2025-07-01 21:30  长安19路  阅读(11)  评论(0)    收藏  举报