知识大全 次小生成树 Tree-LCA的位运算

Posted

篇首语:无限相信书籍的力量,是我的教育信仰的真谛之一。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 次小生成树 Tree-LCA的位运算相关的知识,希望对你有一定的参考价值。

次小生成树 Tree-LCA的位运算  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  关于次小生成树 Tree LCA的位运算我们有实例!

  小 C 最近学了很多最小生成树的算法 Prim 算法 Kurskal 算法 消圈算法 等等 正当小 C 洋洋得意之时 小 P 又来泼小 C 冷水了 小 P 说 让小 C 求出一 个无向图的次小生成树 而且这个次小生成树还得是严格次小的 也就是说 如果最小生成树选择的边集是 EM 严格次小生成树选择的边集是 ES 那么 需要满足 (value(e) 表示边 e的权值) 这下小 C 蒙了 他找到了你 希望你帮他解决这个问题

  Input

  第一行包含两个整数N 和M 表示无向图的点数与边数 接下来 M行 每行 个数x y z 表示 点 x 和点y之间有一条边 边的权值 为z

  Output

  包含一行 仅一个数 表示严格次小生成树的边权和 (数 据保证必定存在严格次小生成树)

  Sample Input

  

  

  

  

  

  

  

  Sample Output

  

  HINT

  数据中无向图无自环;

   % 的数据N≤ M≤ ;

   % 的数据N≤ M≤ ;

   % 的数据N≤ M≤ 边权值非负且不超过 ^

  

  Source

  这题的关键就在于求Lca 记录路径上的最小与严格次小值

  用f[i][j]表示i的第 ^j个儿子( 表示 不存在)

  那么f[i][j]=f[ f[i][ j ] ][j ]

  dp[i][j]和dp [i][j]表示点i到f[i][j]的最小和严格次小值(不存在= ) 那么只需特判即可

  [cpp]

  int lca(int x int y int &nowdp int &nowdp )

  

  if (deep[x]<deep[y]) swap(x y);

  int t=deep[x] deep[y]; //差的数量

  for (int i= ;t;i++)

  if (t&bin[i]) //转化为位运算 bin[i]表示 <<i 把t看成 进制

  

  x=f[x][i];

  t =bin[i];

  

  int i=Li ; //Li 表示 最高存到 ^(Li )个父亲

  while (x^y) //x和y不相等时

  

  while (f[x][i]==f[y][i]&&i) i ; //当i== 时只能向上跳

  x=f[x][i];y=f[y][i];

  

  

  程序

  [cpp]

  #include<cstdio>

  #include<cstdlib>

  #include<cstring>

  #include<iostream>

  #include<algorithm>

  #include<functional>

  using namespace std;

  #define MAXN ( + )

  #define MAXM ( + )

  #define Li ( )

  #define INF ( )

  int edge[MAXM] pre[MAXM] weight[MAXM] next[MAXM] size= ;

  int addedge(int u int v int w)

  

  edge[++size]=v;

  weight[size]=w;

  next[size]=pre[u];

  pre[u]=size;

  

  int addedge (int u int v int w)

  

  addedge(u v w);

  addedge(v u w);

  

  int f[MAXN][Li]= dp[MAXN][Li]= dp [MAXN][Li]= deep[MAXN] n m;

  struct E

  

  int u v w;

  friend bool operator<(E a E b)return a w<b w;

  e[MAXM];

  bool b[MAXM] vis[MAXN];

  int queue[MAXN] head tail;

  void bfs()

  

  memset(vis sizeof(vis));

  head=tail= ;queue[ ]= ;vis[ ]= ;deep[ ]= ;

  while (head<=tail)

  

  int &u=queue[head];

  if (u!= )

  

  for (int i= ;i< ;i++)

  

  if (f[u][i ])

  

  f[u][i]=f[f[u][i ]][i ];

  

  if (f[u][i]== ) break;

  if (f[u][i])

  

  dp[u][i]=max(dp[u][i ] dp[f[u][i ]][i ]);

  

  if (i== )

  

  if (dp[u][ ]!=dp[f[u][ ]][ ]) dp [u][ ]=min(dp[u][ ] dp[f[u][ ]][ ]);

  else dp [u][ ]= ;

  

  else

  

  dp [u][i]=max(dp [u][i ] dp [f[u][i ]][i ]);

  if (dp[u][i ]!=dp[f[u][i ]][i ]) dp [u][i]=max(dp [u][i] min(dp[u][i ] dp[f[u][i ]][i ]));

  

  

  

  for (int p=pre[u];p;p=next[p])

  

  int &v=edge[p];

  if (!vis[v])

  

  queue[++tail]=v;

  vis[v]= ;deep[v]=deep[u]+ ;

  f[v][ ]=u;dp[v][ ]=weight[p];dp [v][ ]= ;

  

  

  head++;

  

  

  int bin[Li];

  void check(int &nowdp int &nowdp int c)

  

  if (c<=nowdp ) return;

  else if (nowdp <c&&c<nowdp) nowdp =c;

  else if (c==nowdp) return;

  else if (nowdp<c) nowdp =nowdp;nowdp=c;

  

  int lca(int x int y int &nowdp int &nowdp )

  

  nowdp=nowdp = ;

  if (deep[x]<deep[y]) swap(x y);

  int t=deep[x] deep[y];

  for (int i= ;t;i++)

  if (t&bin[i])

  

  check(nowdp nowdp dp[x][i]);

  check(nowdp nowdp dp [x][i]);

  x=f[x][i];

  t =bin[i];

  

  int i=Li ;

  while (x^y)

  

  while (f[x][i]==f[y][i]&&i) i ;

  check(nowdp nowdp dp[x][i]);

  check(nowdp nowdp dp [x][i]);

  check(nowdp nowdp dp[y][i]);

  check(nowdp nowdp dp [y][i]);

  x=f[x][i];y=f[y][i];

  

  

  int father[MAXN];

  long long sum_edge= ;

  int getfather(int x)

  

  if (father[x]==x) return x;

  father[x]=getfather(father[x]);

  return father[x];

  

  void union (int x int y)

  

  father[father[x]]=father[father[y]];

  

  int main()

  

  scanf( %d%d &n &m);

  for (int i= ;i<=n;i++) father[i]=i;

  memset(b sizeof(b));

  memset(next sizeof(next));

  for (int i= ;i<Li;i++) bin[i]= <<i;

  for (int i= ;i<=m;i++)

  

  scanf( %d%d%d &e[i] u &e[i] v &e[i] w);

  

  sort(e+ e+ +m);

  for (int i= ;i<=m;i++)

  

  if (getfather(e[i] u)!=getfather(e[i] v)) union (e[i] u e[i] v);addedge (e[i] u e[i] v e[i] w);sum_edge+=e[i] w;

  else b[i]= ;

  

  bfs();

  long long mindec= ;

  for (int i= ;i<=m;i++)

  if (b[i])

  

  int nowdp nowdp ;

  lca(e[i] u e[i] v nowdp nowdp );

  if (nowdp==e[i] w) nowdp=nowdp ;

  if (nowdp== ) continue;

  if (mindec== ||mindec>e[i] w nowdp) mindec=e[i] w nowdp;

  

  printf( %lld\\n sum_edge+mindec);

  return ;

cha138/Article/program/Java/hx/201311/26453

相关参考