CodeChef GRAPHCNT
题目大意:
一张n个点m条边的有向图,问有多少对(x,y)存在有一条从1到x的路径,有一条1到y的路径,他们俩不相交。
题解:
……于是为了这题我去学习了一下支配树,感觉很妙啊。
设定了一个起点之后,u支配点就是从起点到u的必经点。支配树就是每个点都向自己最近的支配点连边,这有一个线性算法……这篇博客 还不错。
求出支配树之后就是一个问树上多少点对lca是1……嗯也挺难的对吧……
贴个代码吧。
1 program j01; 2 const maxn=1000086;maxm=20000086; 3 var q,next:array[0..maxm]of longint; 4 head,pre,dom:array[0..maxn]of longint; 5 semi,idom:array[0..maxn]of longint; 6 f,fa,best:array[0..maxn]of longint; 7 dfn,id:array[0..maxn]of longint; 8 ans:int64; 9 size:array[0..maxn]of longint; 10 tt,n,m,i,u,v,tot:longint; 11 12 procedure addd(var h:longint;v:longint); 13 begin 14 inc(tt);q[tt]:=v;next[tt]:=h;h:=tt; 15 end; 16 17 procedure dfs(i:longint); 18 var j:longint; 19 begin 20 inc(tot);dfn[i]:=tot;id[tot]:=i;j:=head[i]; 21 while j>0 do 22 begin 23 if dfn[q[j]]=0 then begin fa[q[j]]:=i;dfs(q[j]);end;j:=next[j]; 24 end; 25 end; 26 27 function find(i:longint):longint; 28 var v:longint; 29 begin 30 if f[i]=i then exit(i); 31 v:=find(f[i]); 32 if dfn[semi[best[f[i]]]]<dfn[semi[best[i]]] then best[i]:=best[f[i]]; 33 f[i]:=v;exit(v); 34 end; 35 36 procedure tarjan; 37 var u,j:longint; 38 begin 39 for i:=tot downto 2 do 40 begin 41 u:=id[i];j:=pre[u]; 42 while j>0 do 43 begin 44 if dfn[q[j]]=0 then begin j:=next[j];continue;end; 45 find(q[j]); 46 if dfn[semi[best[q[j]]]]<dfn[semi[u]] then semi[u]:=semi[best[q[j]]]; 47 j:=next[j]; 48 end; 49 addd(dom[semi[u]],u); 50 f[u]:=fa[u];u:=id[i-1];j:=dom[u]; 51 while j>0 do 52 begin 53 find(q[j]); 54 if semi[best[q[j]]]=u then idom[q[j]]:=u 55 else idom[q[j]]:=best[q[j]]; 56 j:=next[j]; 57 end; 58 end; 59 for i:=2 to tot do 60 begin 61 u:=id[i];if idom[u]<>semi[u] then idom[u]:=idom[idom[u]]; 62 end; 63 end; 64 65 begin 66 readln(n,m); 67 for i:=1 to m do 68 begin 69 readln(u,v);addd(head[u],v);addd(pre[v],u); 70 end; 71 dfs(1); 72 for i:=1 to n do 73 begin 74 f[i]:=i;semi[i]:=i;best[i]:=i; 75 end; 76 tarjan; 77 ans:=int64(tot)*(tot-1)div 2; 78 for i:=tot downto 2 do 79 begin 80 u:=id[i];inc(size[u]); 81 if idom[u]=1 then ans:=ans-(int64(size[u])*(size[u]-1)div 2); 82 inc(size[idom[u]],size[u]); 83 end; 84 writeln(ans); 85 //for i:=1 to n do writeln(i,':',idom[i]); 86 end.