uva11987 并查集小技巧
大意:维护一种数据结构,支持 几乎是常数级别的 集合合并、将一个元素转移到另一个集合、询问每个集合的和与元素个数。
思路:使用并查集,转移元素时留下一个空节点,同时增加一个节点,将p转移到新根。用pos[p]记录p数字现在的实际位置即可。
program p11987; Var n,m,i,p,q,op,top:longint; f,c,pos,s:array[0..500002] of longint; Function find(P:longint):longint; begin if f[p]=p then exit(p); f[p]:=find(f[p]); exit(f[p]); end; Procedure union(p,q:longint); var fp,fq:longint; begin fp:=find(pos[p]); fq:=find(pos[q]); if fp=fq then exit; if c[fp]<c[fq] then begin f[fp]:=fq; inc(c[fq],c[fp]); inc(s[fq],s[fp]); end else begin f[fq]:=fp; inc(c[fp],c[fq]); inc(s[fp],s[fq]); end; end; Procedure move(p,q:longint);inline; var fp,fq:longint; begin fp:=find(pos[p]); fq:=find(pos[q]); if fp=fq then exit; dec(c[fp]); dec(s[fp],p); inc(c[fq]); inc(s[fq],p); inc(top); pos[p]:=top; f[pos[p]]:=fq; end; begin while not eof do begin readln(n,m);top:=n; for i:=1 to n do begin f[i]:=i;c[i]:=1;pos[i]:=i;s[i]:=i; end; while m>0 do begin dec(m); read(op); case op of 1:begin readln(p,q); union(p,q); end; 2:begin readln(p,q); move(p,q); end; 3:begin readln(p); writeln(c[find(pos[p])],' ',s[find(pos[p])]); end; end; end; end; end.