BZOJ1016 [JSOI2008]最小生成树计数

江苏就是江苏啊,题目质量高。

看到题的时候只YY出了第一个性质:MST中边权相同的的边的个数是一定的。(证略,可以用反证法)

后来上网找题解,发现还有第二个性质:MST如果用Kruskal来做,做完长度为x的所有边以后,此时图的连通性是确定的。(这也是很明显的)

于是嘛。。。先算出每个长度的边的cnt,然后每次暴力枚举哪些边在MST中。

判断方式就是看新加的边有没有使得原来不联通的块联通,然后就做完了。

但是要注意的是,暴力枚举的时候并查集不能路径压缩,因为还要还原。

 

  1 {$inline on}
  2  
  3 const prime = 31011;
  4  
  5 var
  6   n, m, k, t : longint;
  7   i, x, y, z : longint;
  8   count, ans : longint;
  9   a, b, c, p, cnt, fa : array[0..5000] of longint;
 10   flag : boolean;
 11  
 12 procedure add_edge(x, y, z : longint); inline;
 13 begin
 14   inc(t);
 15   a[t] := x;
 16   b[t] := y;
 17   c[t] := z;
 18 end;
 19  
 20 procedure swap(x, y : longint); inline;
 21 var
 22   t : longint;
 23  
 24 begin
 25   t := a[x]; a[x] := a[y]; a[y] := t;
 26   t := b[x]; b[x] := b[y]; b[y] := t;
 27   t := c[x]; c[x] := c[y]; c[y] := t;
 28 end;
 29  
 30 procedure qsort(l, r : longint);
 31 var
 32   i, j, x : longint;
 33  
 34 begin
 35   i := l;
 36   j := r;
 37   x := c[(i + j) shr 1];
 38   repeat
 39     while c[i] < x do inc(i);
 40     while c[j] > x do dec(j);
 41     if i <= j then begin
 42       swap(i, j);
 43       inc(i);
 44       dec(j);
 45     end;
 46   until i > j;
 47   if i < r then qsort(i, r);
 48   if l < j then qsort(l, j);
 49 end;
 50  
 51 function find_fa(x : longint) : longint;
 52 var
 53   f : longint;
 54  
 55 begin
 56   f := fa[x];
 57   if f = x then exit(f);
 58   f := find_fa(f);
 59   fa[x] := f;
 60   exit(f);
 61 end;
 62  
 63 procedure make_mst;
 64 var
 65   i, j, f1, f2 : longint;
 66  
 67 begin
 68   for i := 1 to n do
 69     fa[i] := i;
 70   j := 0;
 71   fillchar(cnt, sizeof(cnt), 0);
 72   for i := 1 to t do begin
 73     if c[i] <> c[i - 1] then inc(j);
 74     f1 := find_fa(a[i]);
 75     f2 := find_fa(b[i]);
 76     if f1 <> f2 then begin
 77       inc(cnt[j]);
 78       fa[f1] := f2;
 79     end;
 80   end;
 81 end;
 82  
 83 function find_f(x : longint) : longint; inline;
 84 begin
 85   while fa[x] <> x do
 86     x := fa[x];
 87   exit(x);
 88 end;
 89  
 90 procedure sub(l, r, num : longint);
 91 var
 92   f1, f2 : longint;
 93  
 94 begin
 95   if num = 0 then begin
 96     inc(count);
 97     if count > prime then
 98       count := count - prime;
 99     exit;
100   end;
101   if l > r then exit;
102   if r - l + 1 > num then sub(l + 1, r, num);
103   f1 := find_f(a[l]);
104   f2 := find_f(b[l]);
105   if f1 <> f2 then begin
106     fa[f1] := f2;
107     sub(l + 1, r, num - 1);
108     fa[f1] := f1;
109   end;
110 end;
111  
112 procedure make_ans;
113 var
114   i, j, f1, f2 : longint;
115  
116 begin
117   for i := 1 to n do
118     fa[i] := i;
119   ans := 1;
120   for i := 1 to k do begin
121     count := 0;
122     sub(p[i], p[i + 1] - 1, cnt[i]);
123     ans := (ans * count) mod prime;
124     for j := p[i] to p[i + 1] - 1 do begin
125       f1 := find_fa(a[j]);
126       f2 := find_fa(b[j]);
127       if f1 <> f2 then fa[f1] := f2;
128     end;
129   end;
130 end;
131  
132 begin
133   readln(n, m);
134   for i := 1 to m do begin
135     read(x, y, z);
136     add_edge(x, y, z);
137   end;
138   qsort(1, t);
139   p[1] := 1;
140   k := 1;
141   for i := 2 to t do
142     if c[i] <> c[i - 1] then begin
143       inc(k);
144       p[k] := i;
145     end;
146   p[k + 1] := t + 1;
147   make_mst;
148   make_ans;
149   flag := true;
150   for i := 1 to n do
151     if fa[i] = i then
152       if flag then flag := false
153       else begin
154         writeln(0);
155         exit;
156       end;
157   writeln(ans);
158 end.
View Code

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。