[图论] [数论] CF1515G Phoenix and Odometers

posted on 2025-07-07 07:01:20 | under | source

题意:给你一张 \(n\)\(m\) 边的有向图,无自环,边带权。回答 \(q\) 次询问,每次给出 \(v,s,t\),判断是否存在一条起终点为 \(v\) 的回路其边权和 \(w\) 满足 \(w+s\equiv 0\pmod t\)\(n,m,q\le 2\times 10^5\)

首先可以对每个强连通分量分别考虑,这样图为强连通图,任意两点存在回路。

根据经验,猜测 \(w\) 即为所有环的一组线性组合。证明容易,对每个环多走 \(t\) 遍对 \(w\) 无影响,一直加到系数为正。那么根据欧拉回路的结论必然存在一种方案。

接下来求出一组基。容易想到只需考虑简单环,也就是只经过一条非树边的环。不过这是无向图还得考虑横叉边。一种构造是定 \(r\) 为根,记 \(d_i\)\(r\to i\) 权值和,\(p_i\)\(i\to r\) 权值和。对于所有边将 \(d_u+w_{u,v}+p_v\) 加入,对所有点将 \(d_i+p_i\) 加入。任意环可表示为所有边减去所有点。

还有更简单的构造,直接把 \(d_u+w_{u,v}-d_v\) 加进来。唯一的问题是这个东西本身代表什么?不难发现是两个环相减。

\(g\) 为所有环的 \(\gcd\),判断存在 \(k\) 使得 \(kg\equiv -s\pmod t\) 即可,这是一次同余方程,有解等价于 \(\gcd(g,t)| {t-s}\)

代码

#include<bits/stdc++.h>
using namespace std;

#define int long long
#define pir pair<int, int>
const int N = 2e5 + 5;
int n, m, u, v, w, T, s, t;
int dfn[N], df, stk[N], low[N], st, bel[N], scc;
int vis[N], xto[N], vis2[N], tox[N], GCD[N];
vector<pir> to[N], to2[N];

inline void dfs(int u){
    low[u] = dfn[u] = ++df, stk[++st] = u; 
    for(auto _ : to[u]){
        int v = _.first, w = _.second;
        if(!dfn[v]) dfs(v), low[u] = min(low[u], low[v]);
        else if(!bel[v]) low[u] = min(low[u], dfn[v]);
    }
    if(low[u] == dfn[u]){
        int tp; ++scc;
        do{
            tp = stk[st--];
            bel[tp] = scc;
        }while(tp ^ u);
    }
}
inline void calc(int id, int rt){
    queue<int> q;
    q.push(rt), vis[rt] = true;
    while(!q.empty()){
        int u = q.front(); q.pop();
        for(auto _ : to[u]){
            int v = _.first, w = _.second;
            if(!vis[v] && bel[v] == id)
                xto[v] = xto[u] + w, vis[v] = true, q.push(v);
        }
    }
    queue<int> q2;
    q2.push(rt), vis2[rt] = true;
    while(!q2.empty()){
        int u = q2.front(); q2.pop();
        GCD[id] = __gcd(GCD[id], xto[u] + tox[u]);
        for(auto _ : to2[u]){
            int v = _.first, w = _.second;
            if(bel[v] == id){
                GCD[id] = __gcd(GCD[id], tox[u] + w + xto[v]);
                if(!vis2[v])
                    tox[v] = tox[u] + w, vis2[v] = true, q2.push(v);
            }
        }
    }
}
signed main(){
    cin >> n >> m;
    for(int i = 1; i <= m; ++i) scanf("%lld%lld%lld", &u, &v, &w), to[u].push_back({v, w}), to2[v].push_back({u, w});
    for(int i = 1; i <= n; ++i) if(!dfn[i]) dfs(i);
    for(int i = 1; i <= n; ++i) if(!vis[i]) calc(bel[i], i); 
    cin >> T;
    while(T--){
        scanf("%lld%lld%lld", &v, &s, &t);
        if((t - s) % __gcd(GCD[bel[v]], t) == 0) puts("YES");
        else puts("NO");
    }
    return 0;
}
posted @ 2026-01-13 11:21  Zwi  阅读(0)  评论(0)    收藏  举报