Problem:
Equivalent Vertices
Background
会津大学付属幼稚園はプログラミングが大好きな子供が集まる幼稚園である。
園児の一人であるゆう君は,プログラミングと同じくらいお絵描きが大好きだ。 
これまでゆう君は丸と六角形と矢印で沢山絵を書いてきた。 
ある日ゆう君はこれらの絵がグラフであることを知る。
丸と六角形は頂点と呼ばれ,矢印は辺と呼ばれているらしい。
ゆう君は2つの頂点間を結ぶようにして矢印を描き、更にその上に0か1を書く。
このように,辺に重み(0または1)があり有向な辺からなるグラフは重み付き有向グラフと呼ばれる。
また,頂点と数字
x
(0または1)が与えられた時,その頂点から出ている矢印のうち,
x
と同じ重みを持つ矢印に従って別の頂点に移動することを
x
に従って遷移する
と言う。
今日ゆう君は0と1からなるどのような数列に従って遷移しても最終的に到達する頂点の種類(丸または六角形)が一緒であるような頂点の対が存在することに気がついた。 
これについてゆう君は一つの問題を思いついた。
Problem
重み付き有向グラフが与えられる。
このグラフの各頂点は0から順番に
n
-1まで番号が割り振られている。
また,各頂点はそこから重みが0の辺と1の辺の合計2本の辺が出て行く。
さらに,頂点には丸い頂点か六角形の頂点の2種類が存在し,各頂点はそれらのいずれかである。
以下にSample Input 2で与えられる重み付き有向グラフを示す。
図1. Sample Input 2
以下の形式で
m
個の質問が与えられるので、それぞれについて答えを出力せよ。
頂点の番号
q
が与えられるので,この頂点と
等価
な頂点の数を出力せよ
2つの頂点
a
,
b
が以下の2つの条件を満たすとき,
a
と
b
は等価である。
a
と
b
は同じ種類の頂点である
0と1からなる長さ1以上の任意の数列について,それに従って
a
と
b
のそれぞれから遷移を開始したとき最終的に到達する頂点の種類が同じである
例えば,図1の頂点3から数列0,0,1,0に従って遷移を開始すると,
3→2→1→1→1の順番で遷移し最終的に到達する頂点は1である。
Sample Input 2 において,頂点0と頂点2,頂点0と頂点4は等価である。
頂点0と頂点4について考える。
これらは両方とも丸い頂点であるため1つめの条件を満たす。
また,これらの頂点から0または1で遷移した結果到達する頂点は1か5である。
頂点1,5はそれぞれどのような数列に従って遷移してもその頂点に止まり続ける。
また,両方とも六角形の頂点である。
これより,頂点0と頂点4はどのような数列に従って遷移しても最終的に到達する頂点は六角形の頂点であるため2つめの条件も満たす。
条件を2つとも満たすので頂点0と頂点4は等価である。
最終的に到達する頂点は種類が同じであれば良いため,頂点の番号が同じである必要はないことに注意せよ。
また,頂点0と頂点1は等価でない。
頂点0は丸い頂点で頂点1は六角形頂点なので,1つめの条件を満たさない。
Input
n
m
v
0
s
0
t
0
v
1
s
1
t
1
…
v
n−1
s
n−1
t
n−1
q
0
q
1
…
q
m−1
v
i
,
s
i
,
t
i
はそれぞれ
i
番の頂点の種類,0による遷移先の頂点番号,1による遷移先の頂点番号
v
i
が0のとき,
i
番の頂点は丸い頂点であり,1のとき六角形の頂点
q
j
は
j
番目の質問で与えられる頂点の番号
Constraints
入力は全て整数として与えられる
1 ≤
n
≤ 3000
1 ≤
m
≤ n
0 ≤
s
i
,
t
i
,
q
j
≤
n
-1
0 ≤
v
i
≤ 1
与えられるグラフの辺が双方向に移動できるものとしたとき,任意の2点を結ぶような辺の集合が存在する, つまり与えられるグラフは連結である
Output
各質問で与えられる頂点の番号
q
j
に対して,それと等価な頂点の数をそれぞれ一行に出力せよ。
Sample Input 1
2 1
0 0 1
0 1 0
0
Sample Output 1
2
Sample Input 2
6 6
0 1 5
1 1 1
0 1 5
0 2 1
0 5 1
1 5 5
0
1
2
3
4
5
Sample Output 2
3
2
3
1
3
2

Submitted solutions:

code_snippet: // AOJ #1583 Equivalent Vertices
// 2025.2.23

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

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int n, m;
    cin >> n >> m;

    vector<int> typ(n), nxt0(n), nxt1(n), grp(n);
    for (int i = 0; i < n; i++) {
        cin >> typ[i] >> nxt0[i] >> nxt1[i];
        grp[i] = typ[i];
    }

    vector<int> queries(m);
    for (int i = 0; i < m; i++) cin >> queries[i];

    bool f = true;
    while(f){
        f = false;
        vector<tuple<int,int,int>> sig(n);
        for (int i = 0; i < n; i++)
            sig[i] = make_tuple(grp[i], grp[nxt0[i]], grp[nxt1[i]]);

        vector<tuple<int,int,int>> uniq = sig;
        sort(uniq.begin(), uniq.end());
        uniq.erase(unique(uniq.begin(), uniq.end()), uniq.end());

        vector<int> newGroup(n);
        for (int i = 0; i < n; i++){
            int pos = int(lower_bound(uniq.begin(), uniq.end(), sig[i]) - uniq.begin());
            newGroup[i] = pos;
        }

        if(newGroup != grp){
            f = true;
            grp = newGroup;
        }
    }

    unordered_map<int, int> freq;
    for (int i = 0; i < n; i++) freq[grp[i]]++;

    for (int i = 0; i < m; i++) cout << freq[grp[queries[i]]] << endl;
    return 0;
}
accuracy: 1
time_ms: 540
memory_kb: 3644
final_rank: 2

code_snippet: #include <iostream>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <vector>
#include <numeric>
#include <algorithm>
#include <queue>
#include <string>
#include <random>
#include <array>
#include <climits>
#include <map>
#include <cassert>
#include <stack>
#include <iomanip>
#include <cfloat>
#include <bitset>
#include <fstream>
#include <chrono>

int main() {
	int n, m; std::cin >> n >> m;
	std::vector<std::tuple<int, int, int>> vertices(n);
	for (auto& [v, s, t] : vertices) {
		std::cin >> v >> s >> t;
	}
	std::vector<int> query(m);
	for (auto& q : query) {
		std::cin >> q;
	}
	std::vector<int> group(n), temp(n), rank(2 * n * n), mode(2 * n * n, -1);
	for (auto iter = 0; iter < n; ++iter) {
		for (auto i = 0; i < n; ++i) {
			const auto [v, s, t] = vertices[i];
			temp[i] = (group[s] * n + group[t] << 1) + v;
		}
		auto r = 0;
		for (auto i = 0; i < n; ++i) {
			if (mode[temp[i]] != iter) {
				mode[temp[i]] = iter;
				rank[temp[i]] = r++;
			}
		}
		for (auto i = 0; i < n; ++i) {
			group[i] = rank[temp[i]];
		}
	}
	std::vector<int> count(n);
	for (const auto g : group) {
		++count[g];
	}
	for (const auto q : query) {
		std::cout << count[group[q]] << '\n';
	}
}
accuracy: 1
time_ms: 60
memory_kb: 143692
final_rank: 5

code_snippet: /*  -*- coding: utf-8 -*-
 *
 * 1583.cc: Equivalent Vertices
 */

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<deque>
#include<algorithm>
#include<numeric>
#include<utility>
#include<complex>
#include<functional>
 
using namespace std;

/* constant */

const int MAX_N = 3000;
const int MAX_GN = MAX_N * (MAX_N + 1) / 2;
const int INF = 1 << 30;

/* typedef */

typedef vector<int> vi;
typedef queue<int> qi;

/* global variables */

int vs[MAX_N], nbrs[MAX_N][2], cs[MAX_N];
vi gnbrs[MAX_GN];
int pids[MAX_N][MAX_N], pis[MAX_GN], pjs[MAX_GN];
bool ds[MAX_GN];

/* subroutines */

/* main */

int main() {
  int n, m;
  scanf("%d%d", &n, &m);

  for (int i = 0; i < n; i++)
    scanf("%d%d%d", vs + i, nbrs[i], nbrs[i] + 1);

  memset(pids, -1, sizeof(pids));
  for (int i = 0, p = 0; i < n; i++)
    for (int j = i; j < n; j++, p++)
      pids[i][j] = p, pis[p] = i, pjs[p] = j;

  qi q;
  for (int i = 0, p = 0; i < n; i++)
    for (int j = i; j < n; j++, p++) {
      for (int di = 0; di < 2; di++) {
	int ri = nbrs[i][di], rj = nbrs[j][di];
	if (ri > rj) swap(ri, rj);
	gnbrs[pids[ri][rj]].push_back(p);
      }
      if (vs[i] != vs[j]) {
	ds[p] = true;
	q.push(p);
      }
    }

  while (! q.empty()) {
    int u = q.front(); q.pop();
    int ui = pis[u], uj = pjs[u];
    vi &gnbru = gnbrs[u];

    for (vi::iterator vit = gnbru.begin(); vit != gnbru.end(); vit++) {
      int &v = *vit;
      if (! ds[v]) {
	ds[v] = true;
	q.push(v);
      }
    }
  }

  for (int i = 0, p = 0; i < n; i++)
    for (int j = i; j < n; j++, p++)
      if (! ds[p]) cs[i]++, cs[j]++;

  while (m--) {
    int q;
    scanf("%d", &q);
    printf("%d\n", cs[q] - 1);
  }
  return 0;
}
accuracy: 1
time_ms: 940
memory_kb: 341500
final_rank: 6

code_snippet: /*  -*- coding: utf-8 -*-
 *
 * 1583.cc: Equivalent Vertices
 */

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<deque>
#include<algorithm>
#include<numeric>
#include<utility>
#include<complex>
#include<functional>
 
using namespace std;

/* constant */

const int MAX_N = 3000;
const int MAX_GN = MAX_N * (MAX_N + 1) / 2;
const int INF = 1 << 30;

/* typedef */

typedef vector<int> vi;
typedef queue<int> qi;

/* global variables */

int vs[MAX_N], nbrs[MAX_N][2], cs[MAX_N];
vi gnbrs[MAX_GN];
int pids[MAX_N][MAX_N], pis[MAX_GN], pjs[MAX_GN];
bool ds[MAX_GN];

/* subroutines */

/* main */

int main() {
  int n, m;
  scanf("%d%d", &n, &m);

  for (int i = 0; i < n; i++)
    scanf("%d%d%d", vs + i, nbrs[i], nbrs[i] + 1);

  memset(pids, -1, sizeof(pids));
  for (int i = 0, p = 0; i < n; i++)
    for (int j = i; j < n; j++, p++)
      pids[i][j] = p, pis[p] = i, pjs[p] = j;

  qi q;
  for (int i = 0, p = 0; i < n; i++)
    for (int j = i; j < n; j++, p++) {
      for (int di = 0; di < 2; di++) {
	int ri = nbrs[i][di], rj = nbrs[j][di];
	if (ri > rj) swap(ri, rj);
	gnbrs[pids[ri][rj]].push_back(p);
      }
      if (vs[i] != vs[j]) {
	ds[p] = true;
	q.push(p);
      }
    }

  while (! q.empty()) {
    int u = q.front(); q.pop();
    int ui = pis[u], uj = pjs[u];
    vi &gnbru = gnbrs[u];

    for (vi::iterator vit = gnbru.begin(); vit != gnbru.end(); vit++) {
      int &v = *vit;
      if (! ds[v]) {
	ds[v] = true;
	q.push(v);
      }
    }
  }

  for (int i = 0, p = 0; i < n; i++)
    for (int j = i; j < n; j++, p++)
      if (! ds[p]) cs[i]++, cs[j]++;

  while (m--) {
    int q;
    scanf("%d", &q);
    printf("%d\n", cs[q] - 1);
  }
  return 0;
}
accuracy: 1
time_ms: 1530
memory_kb: 341132
final_rank: 8

code_snippet: #include<bits/stdc++.h>

#define rep(i,n) for(int i=0;i<(int)n;i++)
#define all(c) (c).begin(),(c).end()
#define mp make_pair
#define pb push_back
#define each(i,c) for(__typeof((c).begin()) i=(c).begin();i!=(c).end();i++)
#define dbg(x) cerr<<__LINE__<<": "<<#x<<" = "<<(x)<<endl

using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef pair<int,int> pi;
const int inf = (int)1e9;
const double INF = 1e12, EPS = 1e-9;

int n, m, v[3000], s[3000], t[3000];

int main(){
	cin >> n >> m;
	rep(i, n) cin >> v[i] >> s[i] >> t[i];
	rep(it, n){
		vector<ll> x;
		vi next;
		rep(i, n) x.pb(v[i] * (ll)1e9 + v[s[i]] * 10000 + v[t[i]]);
		sort(all(x)); x.erase(unique(all(x)), x.end());
		rep(i, n) next.pb(lower_bound(all(x), v[i] * (ll)1e9 + v[s[i]] * 10000 + v[t[i]]) - x.begin());
		rep(i, n) v[i] = next[i];
	}
	unordered_map<int, int> cnt;
	rep(i, n) cnt[v[i]]++;
	rep(i, m){
		int q; cin >> q;
		cout << cnt[v[q]] << endl;
	}
	return 0;
}
accuracy: 1
time_ms: 790
memory_kb: 3296
final_rank: 4

code_snippet: // * template

#include <bits/stdc++.h>
#ifdef LOCAL
#include "dump.hpp"
#else
#define dump(...)
#endif

using namespace std;

template<class T> inline void chmax(T &a, const T &b) { if(a < b) a = b; }
template<class T> inline void chmin(T &a, const T &b) { if(a > b) a = b; }

template<class T, class U> inline void fill_array(T &e, const U &v) { e = v; }
template<class T, class U, size_t s> inline void fill_array(T (&a)[s], const U &v) {for(auto&e:a)fill_array(e,v);}
template<class T, class U, size_t s> inline void fill_array(array<T, s> &a, const U &v) {for(auto&e:a)fill_array(e,v);}
template<class T, class U> inline void fill_array(vector<T> &a, const U &v) {for(auto&e:a)fill_array(e,v);}

// * solve

int main() {
	cin.tie(nullptr);
	ios::sync_with_stdio(false);

	using Graph = vector<vector<int>>;

	int n, q;
	cin >> n >> q;

	set<int> circle, hexagon;
	array<Graph, 2> rG;
	rG.fill(Graph(n));

	for(int v = 0; v < n; ++v) {
		int kind, zero, one;
		cin >> kind >> zero >> one;

		rG[0][zero].emplace_back(v);
		rG[1][one].emplace_back(v);

		if(kind == 0) {
			circle.emplace(v);
		}
		else {
			hexagon.emplace(v);
		}
	}

	vector<int> idx(n);
	vector<set<int>> S;
	queue<int> que;

	const auto update = [&idx, &S, &que](const set<int> &V) {
		for(const auto &v : V) {
			idx[v] = S.size();
		}
		que.emplace(S.size());
		S.emplace_back(V);
	};

	update(circle);
	update(hexagon);

	while(!que.empty()) {
		const set<int> V = S[que.front()];
		que.pop();

		for(const auto &G : rG) {
			map<int, set<int>> M;

			for(const auto &v : V) {
				for(const auto &u : G[v]) {
					M[idx[u]].emplace(u);
				}
			}

			for(const auto &e : M) {
				const int i = e.first;
				set<int> U = e.second;

				assert(0 <= i && i < S.size());
				if(S[i].size() == U.size()) continue;

				set<int> W;
				for(const auto &v : S[i]) {
					if(!U.count(v)) W.emplace(v);
				}
				update(U);
				update(W);
			}
		}
	}

	while(q--) {
		int v;
		cin >> v;
		cout << S[idx[v]].size() << endl;
	}

	return EXIT_SUCCESS;
}
accuracy: 1
time_ms: 1970
memory_kb: 214752
final_rank: 7

code_snippet: #include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <bitset>
#define pb push_back
#define rep(i,n) for (int i = 0; i < n; ++i)
#define rrep(i,n) for (int i = 1; i <= n; ++i)
#define drep(i,n) for (int i = (n)-1; i >= 0; --i)
#define mins(x,y) x = min(x,y)
#define maxs(x,y) x = max(x,y)
#define rng(x) x.begin(),x.end()
#define sz(x) int((x).size())
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
typedef vector<int> vi;
typedef vector<P> vp;
typedef vector<ll> vl;

const int MX = 3005;
const int INF = 1001001001;

int n, q;
int a[MX], b[MX];
ll c[MX];

int main() {
  scanf("%d%d",&n,&q);
  rep(i,n) {
    scanf("%d",&c[i]);
    scanf("%d%d",&a[i],&b[i]);
    // cout<<c[i]<<" "<<a[i]<<" "<<b[i]<<endl;
    // --a[i]; --b[i];
  }
  rep(ti,n) {
    vl x, nc;
    rep(i,n) nc.pb(c[i]*MX*MX+c[a[i]]*MX+c[b[i]]);
    x = nc;
    sort(rng(x));
    rep(i,n) c[i] = lower_bound(rng(x),nc[i])-x.begin();
    // rep(i,n) cout<<c[i]<<" "; cout<<""<<endl;
  }
  rep(i,q) {
    int v;
    scanf("%d",&v);
    // --v;
    int ans = 0;
    rep(j,n) if (c[v] == c[j]) ans++;
    printf("%d\n",ans);
  }
  return 0;
}
accuracy: 1
time_ms: 750
memory_kb: 3352
final_rank: 3

code_snippet: #include <bits/stdc++.h>
#define rep(i,n) for(int i=0;i<(int)(n);i++)
#define rep1(i,n) for(int i=1;i<=(int)(n);i++)
#define all(c) c.begin(),c.end()
#define pb push_back
#define fs first
#define sc second
#define show(x) cout << #x << " = " << x << endl
#define chmin(x,y) x=min(x,y)
#define chmax(x,y) x=max(x,y)
using namespace std;
typedef pair<int,int> P;
int N,M,v[3000],to[3000][2];
bool done[3000][3000];
vector<int> rG[3000][2];
int main(){
	cin>>N>>M;
	rep(i,N) cin>>v[i]>>to[i][0]>>to[i][1];
	rep(i,N) rG[to[i][0]][0].pb(i),rG[to[i][1]][1].pb(i);
	queue<P> que;
	rep(i,N) rep(j,N) if(v[i]!=v[j]) que.push(P(i,j)),done[i][j]=1;
	while(!que.empty()){
		P p=que.front();que.pop();
		int u=p.fs,v=p.sc;
		rep(k,2){
			for(int a:rG[u][k]) for(int b:rG[v][k]){
				if(!done[a][b]){
					que.push(P(a,b));
					done[a][b]=1;
				}
			}
		}
	}
	int c[3000]={};
	rep(i,N){
		rep(j,N) if(!done[i][j]) c[i]++;
	}
	rep(i,M){
		int a;
		cin>>a;
		cout<<c[a]<<endl;
	}
}
accuracy: 1
time_ms: 270
memory_kb: 48736
final_rank: 1