# 家谱(并查集)

Description

Input

Sample Output
Edward Arthur
Walter Arthur
Rodney George
Arthur Arthur

(自己好好想想吧，如果不会并查集的，在网上看看)。

const
p1=150000;
var
h:array [0..p1] of string;{HASH表，记录名字}
h1:array [0..p1] of longint; {HASH表，记录编号}
f:array [1..60000] of string;  {每个编号对应的名字}
p:array [1..60000] of longint;  {并查集}
s:string;
ch:char;
x,y,k,i:longint;
function hash(s:string):longint;
var
i:longint;
begin
hash:=0;
for i:=1 to length(s) do
hash:=hash*4+ord(s[i]);
{哈希函数，这玩意贼神奇，一开始不乘4，超时！

end;

function fd(s:string):longint;{查找}
var x:longint;
begin
x:=hash(s);
while h[x]<>'' do
begin
if h[x]=s then exit(h1[x]);{找到退出编号}
inc(x);
if x>p1 then x:=0;
end;
exit(0); {找不到退出0}
end;

procedure ins(s:string;a:longint);{插入}
var i,x:longint;
begin
x:=hash(s);
while h[x]<>'' do
begin
inc(x);
if x>p1 then x:=0;
end;
h[x]:=s; h1[x]:=a; {找到空位x后记录数据}
end;

function find(x:longint):longint;{并查集+路径压缩}
var y,root,w:longint;
begin
y:=x;
while p[y]>0 do
y:=p[y];
root:=y;
y:=x;
while p[y]>0 do
begin
w:=p[y];
p[y]:=root;
y:=w;
end;
find:=root;
end;

procedure union(x,y:longint);{合并，x是父亲，y是儿子}
var
u,v:longint;
begin
u:=find(x);
v:=find(y);
p[v]:=u; {把儿子的祖先接到y上}
end;

begin
for i:=1 to p1 do
begin h[i]:=''; h1[i]:=0; end;
repeat
if s='\$' then break;
ch:=s[1]; delete(s,1,1); {s删掉第一个字符是人名}
x:=fd(s); {查找}
if x=0 then {找不到给当前人编号，并插入HASH表}
begin inc(k); f[k]:=s; x:=k; ins(s,k); end;
if ch='#' then
y:=x; {记录父亲的编号}
if ch='+' then
union(y,x); {合并父亲和儿子}
if ch='?' then
begin
writeln(s,' ',f[find(x)]);{查找x的最早的祖先，输出其姓名}
end;
until 1=2;
end.