Language: C++

#include<unordered_map>
#include<utility>
template<typename T>
class UnionFind {
 public:
  void unite(const T& a, const T& b) {
    auto x = find(a), y = find(b);
    if(rank_[x] < rank_[y]) std::swap(x, y);
    parent_[y] = x;
    if(rank_[x] == rank_[y]) rank_[x] += 1;
  }
  T find(const T& x) {
    if(!parent_.count(x)) {
      rank_[x] = 1;
      return parent_[x] = x;
    }
    return (parent_[x] == x) ? x : (parent_[x] = find(parent_[x]));
  }
 private:
  std::unordered_map<T, T> parent_;
  std::unordered_map<T, int> rank_;
};

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

using Weight = long long;
using Vertex = int;
struct Edge {Vertex from, to; Weight weight;};
using Graph = std::vector<std::vector<Edge>>;

// 強連結成分分解 O(|V| + |E|)
std::vector<std::vector<Vertex>> strongly_connected_component(const Graph& G) {
  std::vector<std::vector<Vertex>> scc;
  std::stack<Vertex> S;
  std::vector<bool> inS(G.size());
  std::vector<int> num(G.size()), low(G.size());
  int timer = 0;
  // Tarjan
  std::function<int(Vertex v)> dfs = [&](Vertex v) {
    num[v] = low[v] = ++timer;
    S.push(v); inS[v] = true;
    for(const auto& e: G[v]) {
      if(!num[e.to])     low[v] = std::min(low[v], dfs(e.to));
      else if(inS[e.to]) low[v] = std::min(low[v], num[e.to]);
    }
    if(num[v] == low[v]) {
      scc.push_back(std::vector<Vertex>());
      while(true) {
        auto w = S.top(); S.pop(); inS[w] = false;
        scc.back().push_back(w);
        if(v == w) break;
      }
    }
    return low[v];
  };
  for(Vertex v = 0; v < G.size(); ++v) if(!num[v]) dfs(v);
  return scc;
}

int main() {
  int N, M;
  cin >> N >> M;
  Graph G(N);
  vector<int> a(M), b(M);
  for(auto i=0; i<M; ++i) {
    cin >> a[i] >> b[i];
    --a[i]; --b[i];
    G[a[i]].push_back({a[i], b[i]});
  }

  auto scc = strongly_connected_component(G);
  vector<int> group(N);
  for(auto i=0; i<scc.size(); ++i) for(auto v: scc[i]) group[v] = i;

  vector<int> in(N), out(N);
  UnionFind<int> uf;
  for(auto i=0; i<M; ++i) if(group[a[i]] != group[b[i]]) {
    ++in[b[i]];
    ++out[a[i]];
    uf.unite(group[a[i]], group[b[i]]);
  }

  vector<int> indeg(N), outdeg(N);
  for(auto i=0; i<M; ++i) if(group[a[i]] == group[b[i]]) {
    ++outdeg[a[i]];
    ++indeg[b[i]];
  }
  for(auto i=0; i<M; ++i) {
    if(group[a[i]]!=group[b[i]]) {
      if(uf.find(group[a[i]]) == uf.find(group[b[i]])) {
        auto ai = in[a[i]]+1;
        auto ao = out[a[i]]-1;
        auto bi = in[b[i]]-1;
        auto bi = out[b[i]]+1;
        if(1<=ai&&1<=ao&&1<=bi&&1<=bo)cout << "diff" <<endl;
        else                          cout << "same" <<endl;
      } else {
        cout << "same" << endl;
      }
    } else {
      if(1<outdeg[a[i]] && 1<indeg[b[i]]) cout << "same" << endl;
      else                                cout << "diff" << endl;
    }
  }
}


Compiler output:
a.cc: In function 'int main()':
a.cc:95:14: error: conflicting declaration 'auto bi'
   95 |         auto bi = out[b[i]]+1;
      |              ^~
a.cc:94:14: note: previous declaration as 'int bi'
   94 |         auto bi = in[b[i]]-1;
      |              ^~
a.cc:96:36: error: 'bo' was not declared in this scope; did you mean 'bi'?
   96 |         if(1<=ai&&1<=ao&&1<=bi&&1<=bo)cout << "diff" <<endl;
      |                                    ^~
      |                                    bi