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.
View Code

 

posted @ 2017-05-30 18:05 OldJang 阅读(...) 评论(...) 编辑 收藏