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.
原文地址:https://www.cnblogs.com/htfy/p/3063565.html