前言
感觉这是好几个月之前的坑了。现在才填。
Solution
我们用 map 把字符串 hash 一下(应该叫哈希?)。
第一遍时把两边都是字符串的合并在一个并查集里。
第二遍如果两两是字符串或数字就不用讲了。如果是一个数字,一个串就将串所在的并查集的根的权值标记为数字,如果有数字就比较是否相同。
Code
#include <map>
#include <cctype>
#include <cstdio>
#include <iostream>
using namespace std;
const int N = 5e4 + 5;
int n, cnt, f[N << 1], num[N << 1];
map <string, int> s;
string a[N], b[N];
int read() {
int x = 0, f = 1; char s;
while((s = getchar()) < '0' || s > '9') if(s == '-') f = -1;
while(s >= '0' && s <= '9') {x = (x << 1) + (x << 3) + (s ^ 48); s = getchar();}
return x * f;
}
void makeSet() {for(int i = 1; i <= (n << 1); ++ i) f[i] = i;}
int findSet(const int x) {return x == f[x] ? x : f[x] = findSet(f[x]);}
void unionSet(const int x, const int y) {
int u = findSet(x), v = findSet(y);
if(u != v) f[u] = v;
}
int main() {
bool ok = 1; int t;
n = read();
makeSet();
for(int i = 1; i <= n; ++ i) {
cin >> a[i];
if(! s[a[i]]) s[a[i]] = ++ cnt;
}
for(int i = 1; i <= n; ++ i) {
cin >> b[i];
if(! s[b[i]]) s[b[i]] = ++ cnt;
}
for(int i = 1; i <= n; ++ i) {
if(isdigit(a[i][0]) || isdigit(b[i][0])) continue;
unionSet(s[a[i]], s[b[i]]);
}
for(int i = 1; i <= n; ++ i) {
if(! isdigit(a[i][0]) && (! isdigit(b[i][0]))) continue;
if(isdigit(a[i][0]) && isdigit(b[i][0])) {
ok = (a[i] == b[i]);
if(! ok) break;
else continue;
}
if(isdigit(a[i][0])) swap(a[i], b[i]);
t = 0;
for(int j = 0, siz = b[i].length(); j < siz; ++ j)
t = (t << 1) + (t << 3) + (b[i][j] ^ 48);
findSet(s[a[i]]);
if(! num[f[s[a[i]]]]) num[f[s[a[i]]]] = t;
else {
if(num[f[s[a[i]]]] == t) continue;
else {ok = 0; break;}
}
}
puts(ok ? "DA" : "NE");
return 0;
}