#include #include #include #include using namespace std; const int N = 500010; int p[N]; // 并查集数组 int d[N]; // 度 char str1[15], str2[15]; // 两个字符串 // int b[N]; // 记录字符串(对应的HASH值)是否出现过,是桶的概念 int id[N], n; // 用于离散化,根据p是否出现,决定是否为其分配新的节点编号,有旧的使旧的,有新的创建后使新的 int idx; // 创建Trie树时的游标 int tr[N][26]; // Trie树 /* 如果平均字符串长度是10,那么在最坏的情况下,Trie树中最多可能有500000 * 10 = 5000000个节点。 这是因为在最坏的情况下,每个字符串都不共享任何前缀,因此每个字符串的每个字符都会在Trie树中创建一个新的节点。 需要注意的是,这是一个上界,实际的节点数量可能会少于这个值,因为许多字符串可能会共享一些前缀,这些前缀在Trie树中只会被存储一次。 */ int insert(string str) { // 插入字典树并返回结尾字符节点编号 int p = 0; for (int i = 0; i < str.size(); i++) { int u = str[i] - 'a'; // 映射成0~25,本题只有小写字母 if (!tr[p][u]) tr[p][u] = ++idx; p = tr[p][u]; } /* 如上面的论述结果,idx:Trie树中有很多的节点,可每个字符串最后的终点只有1个 我们需要知道我们在心中创建的图有多少个节点,一般用n表示,如果我们直接使用Trie树中的p,虽然在数据范围内不会越界,但在1~p之间,肯定存在无效的节点,这是我们不能接受的, 办法就是直接离散化,只保留有用的节点,重新编号:id[N]+cnt */ if (!id[p]) id[p] = ++n; // 节点编号 return id[p]; } // 并查集 int find(int x) { if (x == p[x]) return x; return p[x] = find(p[x]); } int main() { #ifndef ONLINE_JUDGE freopen("POJ2513.in", "r", stdin); #endif for (int i = 0; i < N; i++) p[i] = i; while (~scanf("%s%s", str1, str2)) { int a = insert(str1), b = insert(str2); // 利用Trie树找出字符串的HASH值,其它与纯字符串131进制的代码一致 d[a]++, d[b]++; if (find(a) != find(b)) p[find(a)] = find(b); } int odd = 0, cnt = 0; for (int i = 1; i <= n; i++) { if (p[i] == i) cnt++; if (d[i] % 2) odd++; } int flag = 1; if ((odd != 0 && odd != 2) || cnt != 1) flag = 0; if (n == 0) flag = 1; if (flag) puts("Possible"); else puts("Impossible"); return 0; }