bzoj 3910 并查集+LCA

来源:互联网 发布:乐视没有mac版 编辑:程序博客网 时间:2024/06/05 17:20

题意:给出一棵树,给定起点和要经过的点的序列,已经经过的点就不去了,即在剩下的点中按照顺序依次去访问还没有访问过的点,问要经过多少条边。

很显然的一个做法就是每当我们走一条路径的时候,就把这条路径上所有点都打上已经被经过的标记,对于一个点,如果它的标记为真则不用再走。

所以复杂度高的原因就是一些点会被来回来去的多次被标记,每次处理的复杂度都是O(n)的

但实际上只要一个点被打上标记就不用再管它了,直接找到路径上下一个没有被打过标记的位置

这不就和bzoj 2054 一毛一样了么

所以每当我们走一条新的路径,就用并查集把这一段路径缩成一个大点,用这两个点的lca做并查集的根,

这样就可以保证每个点最多被标记一次

当然算经过的边的时候还是要按原树跳的

{$Q-}var        n,m,pl,x,l,y    :longint;        ans             :int64;        i,j             :longint;        jump            :array[0..500010,0..20] of longint;        d,que           :array[0..500010] of longint;        last,father,from:array[0..500010] of longint;        vis,flag        :array[0..500010] of boolean;        pre,other       :array[0..1000010] of longint;procedure swap(var a,b:longint);var        c:longint;begin   c:=a; a:=b; b:=c;end;function get_father(x:longint):longint;begin   if x=father[x] then exit(x);   father[x]:=get_Father(father[x]);   exit(father[x]);end;procedure connect(x,y:longint);begin   inc(l);   pre[l]:=last[x];   last[x]:=l;   other[l]:=y;end;procedure dfs(x:longint);var        p,q:longint;begin   q:=last[x];   while q<>0 do   begin      p:=other[q];      if not vis[p] then      begin         from[p]:=x;         vis[p]:=true;         jump[p,0]:=x;         d[p]:=d[x]+1;         dfs(p);      end;      q:=pre[q];   end;end;function lca(x,y:longint):int64;var        i:longint;        ans:int64;begin   ans:=0;   if d[x]>d[y] then swap(x,y);   for i:=0 to 20 do     if ((d[y]-d[x]) and (1<<i) <>0) then     begin        inc(ans,1<<i);        y:=jump[y,i];     end;   if x=y then exit(ans);   for i:=20 downto 0 do     if jump[x,i]<>jump[y,i] then     begin        inc(ans,1<<i); inc(ans,1<<i);        x:=jump[x,i]; y:=jump[y,i];     end;   inc(ans,2);   exit(ans);end;procedure work(x,y:longint);var        tl,tt:longint;begin   tl:=0;   while x<>y do   begin      if d[x]>d[y] then swap(x,y);      inc(tl);      que[tl]:=y;      flag[y]:=true;      y:=get_father(from[y]);   end;   flag[x]:=true;   while tl>0 do   begin      father[get_father(que[tl])]:=x; dec(tl);   end;end;begin   read(n,m,pl);   for i:=1 to n-1 do   begin      read(x,y);      connect(x,y);      connect(y,x);   end;   vis[1]:=true; d[1]:=1; dfs(1);   //   for j:=1 to 20 do     for i:=1 to n do jump[i,j]:=jump[jump[i,j-1],j-1];   for i:=1 to n do father[i]:=i;   for i:=1 to m do   begin      read(x);      if not flag[x] then      begin         inc(ans,lca(x,pl)); work(get_father(pl),x); pl:=x;      end;   end;   writeln(ans);end.
——by Eirlys



0 0
原创粉丝点击