QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#722532#2515. Graph Cardsucup-team5062#AC ✓19004ms237148kbC++206.1kb2024-11-07 19:26:212024-11-07 19:26:22

Judging History

你现在查看的是最新测评结果

  • [2024-11-07 19:26:22]
  • 评测
  • 测评结果:AC
  • 用时:19004ms
  • 内存:237148kb
  • [2024-11-07 19:26:21]
  • 提交

answer

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

// ================================================================= UF Library
class UnionFind {
public:
	vector<int> par;

	void init(int sz) {
		par.resize(sz, -1);
	}

	int root(int pos) {
		if (par[pos] == -1) return pos;
		par[pos] = root(par[pos]);
		return par[pos];
	}

	void unite(int u, int v) {
		u = root(u);
		v = root(v);
		if (u != v) par[u] = v;
	}

	bool same(int u, int v) {
		if (root(u) == root(v)) return true;
		return false;
	}
};

// ================================================================= Base Function
long long mod1 = 900000011LL;
long long mod2 = 998244353LL;
long long mod3 = 2147483647LL;
long long pow1[1 << 22];
long long pow2[1 << 22];
long long pow3[1 << 22];
long long Rand[1 << 22];

struct Hash {
	long long v1, v2, v3;
};

bool isprime(long long x) {
	for (long long i = 2; i * i <= x; i++) {
		if (x % i == 0) return false;
	}
	return true;
}

long long get_prime(long long l, long long r) {
	while (true) {
		long long x = (rand() % 32768) * 32768 + (rand() % 32768);
		long long y = x % (r - l + 1) + l;
		if (isprime(y) == true) return y;
	}
}

bool operator==(const Hash &a1, const Hash &a2) {
	if (a1.v1 != a2.v1) return false;
	if (a1.v2 != a2.v2) return false;
	if (a1.v3 != a2.v3) return false;
	return true;
}

bool operator<(const Hash &a1, const Hash &a2) {
	if (a1.v1 < a2.v1) return true;
	if (a1.v1 > a2.v1) return false;
	if (a1.v2 < a2.v2) return true;
	if (a1.v2 > a2.v2) return false;
	if (a1.v3 < a2.v3) return true;
	return false;
}

void Initialize() {
	mod1 = get_prime( 900000000LL, 1000000000LL);
	mod2 = get_prime(1000000000LL, 1100000000LL);
	mod3 = get_prime(1100000000LL, 1200000000LL);
	pow1[0] = 1; for (int i = 1; i <= 2000000; i++) pow1[i] = (222222223LL * pow1[i - 1]) % mod1;
	pow2[0] = 1; for (int i = 1; i <= 2000000; i++) pow2[i] = (222222223LL * pow2[i - 1]) % mod2;
	pow3[0] = 1; for (int i = 1; i <= 2000000; i++) pow3[i] = (222222223LL * pow3[i - 1]) % mod3;
	map<long long, long long> Map;
	long long x = 869120;
	for (int i = 0; i <= 2000000; i++) {
		while (true) {
			long long r = (rand() % 32768) * 32768 + (rand() % 32768);
			long long v = (r + x) % mod1;
			if (Map[v] == 0) {
				Rand[i] = v;
				Map[v] = 1;
				x = (x * 3LL) % mod1;
				break;
			}
		}
	}
}

Hash Apply(Hash a1, Hash a2) {
	Hash a3;
	a3.v1 = (222222223LL * a1.v1 + a2.v1) % mod1;
	a3.v2 = (222222223LL * a1.v2 + a2.v2) % mod2;
	a3.v3 = (222222223LL * a1.v3 + a2.v3) % mod3;
	return a3;
}

Hash CycleHash(vector<Hash> vec) {
	Hash minv = {mod1 - 1, mod2 - 1, mod3 - 1};
	int N = vec.size();

	// Get Hash
	for (int t = 0; t < 2; t++) {
		vector<Hash> cur(2 * N + 1);
		cur[0] = Hash{0LL, 0LL, 0LL};
		for (int i = 0; i < 2 * N; i++) cur[i + 1] = Apply(cur[i], vec[i % N]);
		for (int i = 0; i < N; i++) {
			Hash p;
			p.v1 = (cur[N + i].v1 - cur[i].v1 * pow1[N] + mod1 * mod1) % mod1;
			p.v2 = (cur[N + i].v2 - cur[i].v2 * pow2[N] + mod2 * mod2) % mod2;
			p.v3 = (cur[N + i].v3 - cur[i].v3 * pow3[N] + mod3 * mod3) % mod3;
			minv = min(minv, p);
		}
		reverse(vec.begin(), vec.end());
	}
	return minv;
}

Hash GraphHash(int pos, int pre, vector<vector<int>> &G) {
	vector<Hash> V;
	for (int to : G[pos]) {
		if (to == pre) continue;
		Hash ret = GraphHash(to, pos, G);
		V.push_back(ret);
	}
	sort(V.begin(), V.end());
	Hash p = {2024LL, 2024LL, 2024LL};
	for (int i = 0; i < (int)V.size(); i++) p.v1 = (277277277LL * (p.v1 * p.v1 % mod1) + V[i].v1 * Rand[i]) % mod1;
	for (int i = 0; i < (int)V.size(); i++) p.v2 = (277277277LL * (p.v2 * p.v2 % mod2) + V[i].v2 * Rand[i]) % mod2;
	for (int i = 0; i < (int)V.size(); i++) p.v3 = (277277277LL * (p.v3 * p.v3 % mod3) + V[i].v3 * Rand[i]) % mod3;
	return p;
}


// ================================================================= Others
void dfs(int pos, int goal, int pre, vector<int> &Current, vector<int> &Answer, vector<vector<int>> &G) {
	if (pos == goal) {
		Answer = Current;
		return;
	}
	for (int to : G[pos]) {
		if (to == pre) continue;
		Current.push_back(to);
		dfs(to, goal, pos, Current, Answer, G);
		Current.pop_back();
	}
}

pair<int, Hash> GetTotalHash(int N, vector<pair<int, int>> Edges) {
	UnionFind UF; UF.init(N + 1);
	vector<vector<int>> G(N, vector<int>(0, 0));
	vector<vector<int>> H(N, vector<int>(0, 0));
	vector<int> Path;
	vector<bool> IsCycle(N, false);

	// Get Cycle
	for (int i = 0; i < (int)Edges.size(); i++) {
		if (UF.same(Edges[i].first, Edges[i].second) == true) {
			vector<int> tmp = {Edges[i].first};
			dfs(Edges[i].first, Edges[i].second, -1, tmp, Path, G);
		}
		else {
			UF.unite(Edges[i].first, Edges[i].second);
			G[Edges[i].first].push_back(Edges[i].second);
			G[Edges[i].second].push_back(Edges[i].first);
		}
	}

	// Get New Graph
	for (int idx : Path) IsCycle[idx] = true;
	for (pair<int, int> e : Edges) {
		if (IsCycle[e.first] == true && IsCycle[e.second] == true) continue;
		H[e.first].push_back(e.second);
		H[e.second].push_back(e.first);
	}

	// Get Hash
	vector<Hash> E(Path.size());
	for (int i = 0; i < (int)Path.size(); i++) {
		E[i] = GraphHash(Path[i], -1, H);
	}
	return make_pair(Path.size(), CycleHash(E));
}

int main() {
	int T; scanf("%d", &T);
	Initialize();
	for (int t = 1; t <= T; t++) {
		int N; scanf("%d", &N);
		vector<vector<pair<int, int>>> Graph(N);

		// Input Graph
		for (int i = 0; i < N; i++) {
			int K; scanf("%d", &K);
			Graph[i].resize(K, make_pair(0, 0));
			for (int j = 0; j < K; j++) {
				scanf("%d%d", &Graph[i][j].first, &Graph[i][j].second);
				Graph[i][j].first -= 1;
				Graph[i][j].second -= 1;
			}
		}

		// Get Hash
		vector<tuple<int, int, Hash>> Answer(N);
		for (int i = 0; i < N; i++) {
			pair<int, Hash> v = GetTotalHash(Graph[i].size(), Graph[i]);
			Answer[i] = make_tuple(Graph[i].size(), v.first, v.second);
		}
		sort(Answer.begin(), Answer.end());
		Answer.erase(unique(Answer.begin(), Answer.end()), Answer.end());

		// Output
		printf("%d\n", (int)Answer.size());
	}
	return 0;
}

Details

Tip: Click on the bar to expand more detailed information

Test #1:

score: 100
Accepted
time: 1902ms
memory: 201412kb

input:

1
2
4 1 2 2 3 3 1 1 4
4 1 2 2 3 3 1 2 4

output:

1

result:

ok single line: '1'

Test #2:

score: 0
Accepted
time: 1888ms
memory: 193592kb

input:

2
2
4 1 2 2 3 3 1 1 4
5 1 2 2 3 3 1 2 4 2 5
3
9 1 2 2 5 5 7 7 6 6 3 3 1 2 4 7 9 9 8
9 1 4 4 2 2 3 3 5 5 7 7 6 6 4 7 8 8 9
9 1 2 2 5 5 4 4 1 4 7 7 8 8 6 8 9 5 3

output:

2
2

result:

ok 2 lines

Test #3:

score: 0
Accepted
time: 11352ms
memory: 201092kb

input:

30
332526
3 3 2 3 1 2 1
3 2 3 3 1 1 2
3 1 3 1 2 3 2
3 3 2 2 1 1 3
3 2 1 2 3 1 3
3 1 3 1 2 3 2
3 1 2 2 3 3 1
3 2 1 2 3 1 3
3 3 1 3 2 1 2
3 1 3 1 2 3 2
3 1 3 3 2 2 1
3 1 2 2 3 3 1
3 3 1 3 2 1 2
3 2 1 2 3 1 3
3 3 2 2 1 1 3
3 1 2 1 3 2 3
3 1 2 1 3 2 3
3 2 3 2 1 3 1
3 1 2 1 3 2 3
3 3 1 1 2 2 3
3 1 3 1 2 ...

output:

1
4
5
89
93
242
628
1575
3401
5703
7718
8888
9258
9355
9356
9203
9211
89
239
648
1739
4541
10352
19037
27089
31567
33030
33068
32480
31503

result:

ok 30 lines

Test #4:

score: 0
Accepted
time: 9993ms
memory: 200012kb

input:

30
333333
3 2 1 2 3 3 1
3 1 2 3 2 3 1
3 3 2 1 3 1 2
3 2 3 2 1 3 1
3 2 3 2 1 1 3
3 1 2 3 2 3 1
3 3 1 2 1 3 2
3 1 3 1 2 3 2
3 1 3 2 3 1 2
3 2 1 3 2 3 1
3 2 3 1 2 1 3
3 3 1 1 2 3 2
3 3 2 3 1 1 2
3 2 1 3 1 3 2
3 3 2 1 2 3 1
3 3 2 1 2 1 3
3 2 3 2 1 1 3
3 1 2 3 2 3 1
3 3 1 1 2 3 2
3 1 3 1 2 2 3
3 1 2 3 2 ...

output:

1
2
5
13
33
89
240
653
1771
4753
11868
24982
40524
51128
54690
54119
52143
49848
47551
45441
43471
41664
40000
38461
37037
35714
34482
33333
32258
31250

result:

ok 30 lines

Test #5:

score: 0
Accepted
time: 19004ms
memory: 237148kb

input:

30
2
500000 12446 494050 179161 216388 282442 232792 428247 130742 87062 493860 276791 469755 342468 58973 93535 429405 5662 112197 121541 62083 28611 427877 376918 349780 372239 58010 457751 308686 448844 473714 151350 480692 152372 415617 311966 298916 302690 200753 75481 396263 318635 79619 39930...

output:

1
2
2
1
1
2
2
1
1
2
2
1
1
2
2
1
1
2
2
1
1
2
2
1
1
2
2
1
1
2

result:

ok 30 lines

Test #6:

score: 0
Accepted
time: 2149ms
memory: 217972kb

input:

1
4
240000 1 2 2 3 3 4 4 7 1 5 2 6 7 8 8 9 9 10 10 13 7 11 8 12 13 14 14 15 15 16 16 19 13 17 14 18 19 20 20 21 21 22 22 25 19 23 20 24 25 26 26 27 27 28 28 31 25 29 26 30 31 32 32 33 33 34 34 37 31 35 32 36 37 38 38 39 39 40 40 43 37 41 38 42 43 44 44 45 45 46 46 49 43 47 44 48 49 50 50 51 51 52 52...

output:

2

result:

ok single line: '2'