最近公共祖先------------闇の連鎖

伝説のダークチェーンはダークとして知られています。
闇は人間の心の闇の産物であり、古代と現代の勇敢な男たちはそれを打ち破ろうとしました。
調査の結果、Darkには無向グラフ構造があることがわかりました。グラフにはN個のノードと2種類のエッジがあります。1種類のエッジはメインエッジと呼ばれ、もう1種類は追加エッジと呼ばれます。
ダークにはN-1個のメインエッジがあり、ダークの2つのノード間にはメインエッジのみで構成されるパスがあります。
さらに、ダークにはM個の追加エッジがあります。
あなたの仕事は、ダークを2つの切り離された部分にカットすることです。
最初、Darkの追加のエッジは無敵です。切り取るメインエッジは1つだけ選択できます。
メインエッジをカットオフすると、ダークは防御モードに入り、メインエッジは無敵になり、追加のエッジをカットオフできます。
しかし、あなたの能力はダークの追加のエッジをカットすることしかできません。
今、あなたはダークを倒すことができるオプションの数を知りたいです。
最初のステップでメインエッジをカットした後、2つのステップでダークをカットした場合でも、ダークを倒すために追加のエッジをカットする必要があることに注意してください。
入力形式
最初の行には、2つの整数NとMが含まれています。
次に、N-1行、各行には2つの整数AとBが含まれ、AとBの間にメインエッジがあることを示します。
次に、M行は同じ形式でエッジを追加します。
出力形式
回答を示す整数を出力します。
データ範囲
N≤100000、M≤200000、データ保証回答が231-1を超えないN≤100000、M≤200000、データ保証回答が231-1を超えない
入力サンプル:
4 1
1 2
2 3
1 4
3 4

出力例:
3

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100010, M = 2 * N;
int n, m;
int h[N], e[M], ne[M], idx;
int depth[N], fa[N][17];
int d[N];
int q[N];
int ans;
void add(int a, int b){
 e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
void bfs(){
 memset(depth, 0x3f, sizeof depth);
 depth[0] = 0, depth[1] = 1;
 q[0] = 1;
 int hh = 0, tt = 0; 
 while(hh <= tt){
  int t = q[hh ++];
  for (int i = h[t]; ~i; i = ne[i]){
   int j = e[i];
   if (depth[j] > depth[t] + 1){
    depth[j] = depth[t] + 1;
    q[++ tt] = j;
    fa[j][0] = t;
    for (int k = 1; k <= 16; k ++)
     fa[j][k] = fa[fa[j][k - 1]][k - 1];
   }
  }
 }
}
int lca(int a, int b){
 if (depth[a] <= depth[b])   swap(a, b);
 for (int k = 16; k >= 0; k --)
    if (depth[fa[a][k]] >= depth[b])
      a = fa[a][k];
  if (a == b)   return a;
  for (int k = 16; k >= 0; k --)
     if (fa[a][k] != fa[b][k]){
      a = fa[a][k];
      b = fa[b][k];
  }
   return fa[a][0];
}
int dfs(int u, int father){
 int res = d[u];
 for (int i = h[u]; ~i; i = ne[i]){
  int j = e[i];
  if (j != father){
   int s = dfs(j, u);
   if (s == 0)   ans += m;
   else   if (s == 1)   ans ++;
   res += s;
  }
 }
  return res;
}
int main(){
 scanf("%d%d", &n, &m);
 memset(h, -1, sizeof h);
  for (int i = 0; i < n - 1; i ++){
  int a, b;
  scanf("%d%d", &a, &b);
  add(a, b), add(b, a);
 }
  bfs();
  for (int i = 0; i < m; i ++){
  int a, b;
  scanf("%d%d", &a, &b);
  int p = lca(a, b);
  d[a] ++, d[b] ++, d[p] -= 2;
 }
  dfs(1, -1);
  printf("%d\n", ans);
  return 0;
} 
164の元の記事が公開されました いいね112 訪問6759

おすすめ

転載: blog.csdn.net/qq_45772483/article/details/105591204