zoukankan      html  css  js  c++  java
  • BZOJ1016 [JSOI2008]最小生成树计数

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

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

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

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

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

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

     

      1 /**************************************************************
      2     Problem: 1016
      3     User: rausen
      4     Language: Pascal
      5     Result: Accepted
      6     Time:8 ms
      7     Memory:344 kb
      8 ****************************************************************/
      9  
     10 {$inline on}
     11  
     12 const prime = 31011;
     13  
     14 var
     15   n, m, k, t : longint;
     16   i, x, y, z : longint;
     17   count, ans : longint;
     18   a, b, c, p, cnt, fa : array[0..5000] of longint;
     19   flag : boolean;
     20  
     21 procedure add_edge(x, y, z : longint); inline;
     22 begin
     23   inc(t);
     24   a[t] := x;
     25   b[t] := y;
     26   c[t] := z;
     27 end;
     28  
     29 procedure swap(x, y : longint); inline;
     30 var
     31   t : longint;
     32  
     33 begin
     34   t := a[x]; a[x] := a[y]; a[y] := t;
     35   t := b[x]; b[x] := b[y]; b[y] := t;
     36   t := c[x]; c[x] := c[y]; c[y] := t;
     37 end;
     38  
     39 procedure qsort(l, r : longint);
     40 var
     41   i, j, x : longint;
     42  
     43 begin
     44   i := l;
     45   j := r;
     46   x := c[(i + j) shr 1];
     47   repeat
     48     while c[i] < x do inc(i);
     49     while c[j] > x do dec(j);
     50     if i <= j then begin
     51       swap(i, j);
     52       inc(i);
     53       dec(j);
     54     end;
     55   until i > j;
     56   if i < r then qsort(i, r);
     57   if l < j then qsort(l, j);
     58 end;
     59  
     60 function find_fa(x : longint) : longint;
     61 var
     62   f : longint;
     63  
     64 begin
     65   f := fa[x];
     66   if f = x then exit(f);
     67   f := find_fa(f);
     68   fa[x] := f;
     69   exit(f);
     70 end;
     71  
     72 procedure make_mst;
     73 var
     74   i, j, f1, f2 : longint;
     75  
     76 begin
     77   for i := 1 to n do
     78     fa[i] := i;
     79   j := 0;
     80   fillchar(cnt, sizeof(cnt), 0);
     81   for i := 1 to t do begin
     82     if c[i] <> c[i - 1] then inc(j);
     83     f1 := find_fa(a[i]);
     84     f2 := find_fa(b[i]);
     85     if f1 <> f2 then begin
     86       inc(cnt[j]);
     87       fa[f1] := f2;
     88     end;
     89   end;
     90 end;
     91  
     92 function find_f(x : longint) : longint; inline;
     93 begin
     94   while fa[x] <> x do
     95     x := fa[x];
     96   exit(x);
     97 end;
     98  
     99 procedure sub(l, r, num : longint);
    100 var
    101   f1, f2 : longint;
    102  
    103 begin
    104   if num = 0 then begin
    105     inc(count);
    106     if count > prime then
    107       count := count - prime;
    108     exit;
    109   end;
    110   if l > r then exit;
    111   if r - l + 1 > num then sub(l + 1, r, num);
    112   f1 := find_f(a[l]);
    113   f2 := find_f(b[l]);
    114   if f1 <> f2 then begin
    115     fa[f1] := f2;
    116     sub(l + 1, r, num - 1);
    117     fa[f1] := f1;
    118   end;
    119 end;
    120  
    121 procedure make_ans;
    122 var
    123   i, j, f1, f2 : longint;
    124  
    125 begin
    126   for i := 1 to n do
    127     fa[i] := i;
    128   ans := 1;
    129   for i := 1 to k do begin
    130     count := 0;
    131     sub(p[i], p[i + 1] - 1, cnt[i]);
    132     ans := (ans * count) mod prime;
    133     for j := p[i] to p[i + 1] - 1 do begin
    134       f1 := find_fa(a[j]);
    135       f2 := find_fa(b[j]);
    136       if f1 <> f2 then fa[f1] := f2;
    137     end;
    138   end;
    139 end;
    140  
    141 begin
    142   readln(n, m);
    143   for i := 1 to m do begin
    144     read(x, y, z);
    145     add_edge(x, y, z);
    146   end;
    147   qsort(1, t);
    148   p[1] := 1;
    149   k := 1;
    150   for i := 2 to t do
    151     if c[i] <> c[i - 1] then begin
    152       inc(k);
    153       p[k] := i;
    154     end;
    155   p[k + 1] := t + 1;
    156   make_mst;
    157   make_ans;
    158   flag := true;
    159   for i := 1 to n do
    160     if fa[i] = i then
    161       if flag then flag := false
    162       else begin
    163         writeln(0);
    164         exit;
    165       end;
    166   writeln(ans);
    167 end.
    View Code
    By Xs酱~ 转载请说明 博客地址:http://www.cnblogs.com/rausen
  • 相关阅读:
    Java8 lambda表达式10个示例
    我和阿里云RDS的故事
    Spring Mvc 传递参数要controller出现了400,日期参数全局处理,格式化yyyy-MM-dd 和yyyy-MM-dd HH:mm:ss
    剑指Offer_36_两个链表的第一个公共结点
    剑指Offer_35_数组中的逆序对
    剑指Offer_34_找出字符串中第一个只出现一次的字符
    剑指Offer_33_丑数
    剑指Offer_32_把数组排成最小的数
    剑指Offer_31_整数中1出现的次数(从1到n整数中1出现的次数)
    剑指Offer_30_连续子数组的最大和
  • 原文地址:https://www.cnblogs.com/rausen/p/4001287.html
Copyright © 2011-2022 走看看