第14回 Blue Bridge Cup 大会 ソフトウェア大会 地方大会 (C/C++ グループ B)


現在、未記入の問題BとFを除いて、残りの問題は更新されており、非公式データテスト後にすべてAC可能です。交換へようこそ


質問 A. 日付統計

1. トピックの説明

  Xiaolan には長さ 100 の配列があり、配列内の各要素の値は
0 から 9 の範囲内です。配列の要素は、左から右に次のとおりです。

5 6 8 6 9 1 6 1 2 4 9 1 9 8 2 3 6 4 7 7 5 9 5 0 3 8 7 5 8 1 5 8 6 1 8 3 0 3 7 9 2 7 0 5 8 8 5 7 0
9 9 1 9 4 4 6 8 6 3 3 8 5 1 6 3 4 6 7 0 7 8 2 7 6 8 9 5 6 5 6 1 4 0 1 0 0 9 4 8 0 9 1 2 8 5 0 2 5 3
3

次に、この配列から、次の条件を満たすいくつかのサブシーケンスを見つけたいと考えています。

    1. サブシーケンスの長さは8 8です8
    1. . このサブシーケンスは、添え字の順序でyyyymmdd yyyymmddを形成できます。yyyy mm dd形式の日付。
      日付は2023 202320230902、 20231223 20230902 、 20231223などの 2023 年の日付20230902,20231223。yyyy yyyy _ _
      _yyyy は年を表し、mm mmmmは月、dd dddd は日数を表し、月の長さまたは日数が
      1 桁のみの場合は、先頭に 0 を追加する必要があります。

Xiaolan が、上記の条件に従って 2023 年の異なる日付  をいくつ見つけることができるかを計算するのを手伝ってください。
同じ日付に対して 1 回だけカウントする必要があります。

2. 問題解決のアイデア

  8 層サイクルの列挙を考えてみましょう. 途中で枝を切る必要があります.検索速度を上げます. と書くことはお勧めできませんdfs.答えは です235

3. テンプレートコード

  一時的な変更

項目 B.01 文字列のエントロピー

1. トピックの説明

  私は数学を勉強したことがありません。

2. 問題解決のアイデア

3. テンプレートコード

質問 C. 金属の製錬

1. トピックの説明

Xiaolanには、一般的な金属  を出現させるための魔法の炉がありますOは特別な金属XX×このVV
という性質がありますVVVVは正の整数で、VV をVコモン
メタルOOOはたまたま特別な金属XXX、共通金属OOOの数がVVVでは、
製錬を継続できません。
  今NNN製錬レコード、各レコードには 2 つの整数AAABBB 、これは今回AA が一般的な金属OOO、そして最後に製錬されたBBB特殊金属XX×各レコードは独立しています
前回消費されなかったOOOは次の精錬に追加されません。
  このNNN の製錬レコード、変換率VVVの最小値と最大値は何ですか。タイトルは、評価データに解決できない状況がないことを保証します。

2. 問題解決のアイデア

  例を見たことがあれば、答えの 2 つの上限と下限を直接二分できることは明らかです。式の構造はAC = B \frac{A}{C} = Bなので=B.AA __Aは変更されません。最初に最小のCCC 、すべての数式のBB をCCの場合、 Bは変更されません。Cは小さすぎます。明らかにBBの特定のグループが存在します。Bが増加するため、各グループが一貫していることを確認する必要がありますa[i]/x <= b[i]逆に最大のCCCCCCは大きすぎます。明らかにBBの特定のグループが存在します。Bが小さくなり、各グループが一貫していることを確認する必要がありますa[i]/x >= B

3. テンプレートコード

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int, int> PII;
#define pb(s) push_back(s);
#define SZ(s) ((int)s.size());
#define ms(s,x) memset(s, x, sizeof(s))
#define all(s) s.begin(),s.end()
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const int N = 200010;

int n;
int a[N], b[N];
bool check(LL x) {
    
    
	for (int i = 1; i <= n; ++i) {
    
    
		if (a[i] / x > b[i]) return false;
	}
	return true;
}
bool check2(LL x) {
    
    
	for (int i = 1; i <= n; ++i) {
    
    
		if (a[i] / x < b[i]) return false;
	}
	return true;
}
void solve()
{
    
    
	cin >> n;
	for (int i = 1; i <= n; ++i) cin >> a[i] >> b[i];
	LL l = 1, r = 1e9;
	while (l < r) {
    
    
		LL mid = l + r >> 1;
		if (check(mid)) r = mid;
		else l = mid + 1;
	}
	int s = r;
	l = 1, r = 1e9;
	while (l < r) {
    
    
		LL mid = l + r + 1 >> 1;
		if (check2(mid)) l = mid;
		else r = mid - 1;
	}
	cout << s << " " << r << '\n';
}
int main()
{
    
    
	ios_base :: sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	int t = 1;
	while (t--)
	{
    
    
		solve();
	}
	return 0;
}

質問 D. 飛行機の着陸

1. トピックの説明

   NN滑走路が 1 本しかない空港にN機の飛行機が着陸しようとしています。うちii飛行機i はT i TiT i はいつでも空港の上空に到着し、到着すると、残りの燃料はD i DiD i単位の時間、つまり、T i Ti
である可能性があります。着陸はT i時刻に開始され、T i + D i Ti + Diティー_+D i はその瞬間に着陸を開始します。着陸プロセスにはLi LiL i
単位時間。
  1 つの飛行機が着陸を完了するとすぐに、別の飛行機が同時に着陸を開始できますが、
前の飛行機が着陸を完了する前ではありません。NN
  で判断してくださいN機すべてが安全に着陸できるかどうか。

2. 問題解決のアイデア

NN   を参照最大N10は であり、T最大は10N です.完全な配置を考慮してすべての落下状況を列挙すると、一致する状況が 1 つある限り、計算の複雑さは約 10! × 10 × 10 10 ! \times10\times1010 !×10×10が に等しい場合3e8、理論は通用します。

3. テンプレートコード

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int, int> PII;
#define pb(s) push_back(s);
#define SZ(s) ((int)s.size());
#define ms(s,x) memset(s, x, sizeof(s))
#define all(s) s.begin(),s.end()
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const int N = 200010;


int n;
int a[N], b[N], c[N];
void solve()
{
    
    
	cin >> n;
	for (int i = 0; i < n; ++i) cin >> a[i] >> b[i] >> c[i];
	std::vector<int> d(n);
	auto check = [&]() {
    
    
		int v = 0;
		for (int i = 0; i < n; ++i) {
    
    
			int x = d[i];
			if (i == 0) {
    
    
				v = a[x] + c[x];
			} else {
    
    
				if (a[x] + b[x] < v) return false;
				v = max(v, a[x]) + c[x];
			}
		}
		return true;
	};
	iota(all(d), 0);
	bool f = false;
	do {
    
    
		if (check()) {
    
    
			f = true;
			break;
		}
	} while (next_permutation(all(d)));
	if (f) cout << "YES" << '\n';
	else cout << "NO" << '\n';
}
int main()
{
    
    
	ios_base :: sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	int t = 1;
	cin >> t;
	while (t--)
	{
    
    
		solve();
	}
	return 0;
}

質問 E. ソリティア シーケンス

1. トピックの説明

   長さKKの場合Kの整数シーケンスA 1 、A 2 、...、AK A_1、A_2、...、A_K12... ,KA i A_iの場合にのみ、ソリティア シーケンスと呼びます。の 1 桁目は A i − 1 A_{i-1}と正確に等しいi 1( 2 ≤ i ≤ K ) (2 ≤ i ≤ K)の最後の桁( 2K
   例:12、23、35、56、61、11 12、23、35、56、61、1112 23 35 ,56 61 11はソリティアのシーケンスです;12, 23, 34, 56 12, 23, 34, 5612 23 34 56 56であるため、56 はソリティア シーケンスではありません。56の最初の桁は34 と等しくありません 3434の最後の桁。すべての長さは1 11の整数シーケンスは
   今与えられた長さNNN 的数列 A 1 , A 2 , . . . , A N A_1, A_2, . . . , A_N 12... ,N、残りのシーケンスがソリティアシーケンスになるように、少なくともいくつの数字が削除されるかを計算してください?

2. 問題解決のアイデア

   試験会場で問題を読み終えたとき、少し違和感を覚えましたが、考え方は比較的単純でした。まず、f [ i ] f[i]として定義される数値の最初の桁と最後の桁に注意する必要があります。f [ i ]は数iii , iiで終わる最長のソリティア シーケンスの長さiの範囲は[ 0 , 9 ] [0,9]です。[ 0 ,9 ]各数値について、最初の桁をaaa、最後の数字はbbbの場合、次の伝達方程式があります:
f [ b ] = max ( f [ b ] , f [ a ] + 1 ) f[b]=max(f[b],f[a]+1)f [ b ]=max ( f [ b ] , _f [ a ]+1 )
   最後にf[0], f[1] . . . f[9] f[0], f[1]...f[9]f [ 0 ] f [ 1 ] ... f [ 9 ]最大ans ansan s、答えはn − ans n-ansnアンス _

3. テンプレートコード

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int, int> PII;
#define pb(s) push_back(s);
#define SZ(s) ((int)s.size());
#define ms(s,x) memset(s, x, sizeof(s))
#define all(s) s.begin(),s.end()
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const int N = 200010;

int n;
int a[N], b[N];
int f[10];
void solve()
{
    
    
	cin >> n;
	for (int i = 1; i <= n; ++i) {
    
    
		int x;
		cin >> x;
		b[i] = x % 10;
		string s = to_string(x);
		a[i] = s[0] - '0';
	}
	for (int i = 1; i <= n; ++i) {
    
    
		f[b[i]] = max(f[b[i]], f[a[i]] + 1);
	}
	int ans = 0;
	for (int i = 0; i <= 9; ++i) ans = max(ans, f[i]);
	cout << n - ans << '\n';
}
int main()
{
    
    
	ios_base :: sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	int t = 1;
	while (t--)
	{
    
    
		solve();
	}
	return 0;
}

質問 F. 島の数

1. トピックの説明

仮更新、書いてて気持ち悪い

2. 問題解決のアイデア

3. テンプレートコード

質問 G. 部分文字列の省略形

1. トピックの説明

   プログラマの間では非常に新しい省略形の方法が人気です。文字列の場合、最初と最後の文字のみが予約され、最初と最後の文字の間のすべての文字がこの部分の長さに置き換えられます。たとえば、international - alization international-alizationin tert i o n _a l i z a t i o n はi 18 n i18nと略されますi 18 nKubernetes KubernetesK u ber net es (ハイフンは文字列の一部ではないことに注意してください) は、K 8 s 、L anqiao K8s、Lanqiao と省略ますK 8L an q ia o略してL 5 o L5oL5o _ この質問では、長さがKK
   以上で​​あることを規定しています。Kのすべての文字列は、この省略形の方法を使用できます (長さはKK未満です)。K文字列は、この略記には適していません)。
   与えられた文字列SSSと2文字c1c1c 1およびc 2 c2c 2 、 SSを計算してくださいSc1 c1c 1 はc 2 c2で始まりますc 2の末尾の部分文字列は、この短縮形を使用できますか

2. 問題解決のアイデア

   このG質問をさらに奇妙に感じます。下付き文字がiiであるとします。iの文字はc 1 c1c 1の場合、間隔[ i + k − 1 , n ] [i+k-1,n][+k1 n ]c 2 c2c 2で十分です。プレフィックスと前処理c 2 c2c 2文字、答えを直接追加するだけです。答えが爆発することに注意してくださいint。複雑さO ( n ) O(n)()

3. テンプレートコード

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int, int> PII;
#define pb(s) push_back(s);
#define SZ(s) ((int)s.size());
#define ms(s,x) memset(s, x, sizeof(s))
#define all(s) s.begin(),s.end()
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const int N = 500010;

int k;
string s;
char c1, c2;
int a[N];
void solve()
{
    
    
	cin >> k >> s >> c1 >> c2;
	int n = s.size();
	s = '?' + s;
	for (int i = 1; i <= n; ++i) {
    
    
		a[i] = (s[i] == c2);
		a[i] += a[i - 1];
	}
	LL ans = 0;
	for (int i = 1; i + k - 2 < n; ++i) {
    
    
		if (s[i] == c1) ans += a[n] - a[i + k - 2];
	}
	cout << ans << '\n';
}
int main()
{
    
    
	ios_base :: sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	int t = 1;
	while (t--)
	{
    
    
		solve();
	}
	return 0;
}

質問 H. 整数の削除

1. トピックの説明

   長さNN が与えられた場合Nの整数シーケンスA 1 、A 2 、. . .、AN A_1、A_2、. . . 、A_N12... ,N. 次の操作を繰り返す必要がありますKKK回:
   毎回、シーケンス内の最小の整数を選択し (複数の最小値がある場合は、最初の整数を選択)、それを削除します。そして、削除された値をそれに隣接する整数に追加します。
   アウトプットKKK操作後のシーケンス

2. 問題解決のアイデア

   比較的典型的なトピックのようです. プライオリティ キューを使用して維持し、値と添字を格納してから、配列を使用してcnt各添字の合計を累積します. 最小値がポップアップし、添字がiであるそうcnt[i]でない場合この時点で等しい0, それはそれを意味します 実際の値を追加する必要がありますcnt[i]. それを増やして優先度の列に戻します. クリアする必要があることに注意してくださいcnt[i]. cnt[i]この時点で等しい場合は0、現在の最小要素のポップに成功しています. この時点で、前の要素と次の要素の値を増やす必要があります. リンクされたリストをシミュレートして、最初の要素を記録する必要があります.各要素の後方要素は、添字が上であることを示し、pre[i]iが要素であり、そのne[i]添字が次の要素であるかを示し、ヒープ内の要素の数がなくなるとループが終了します。ヒープ要素の入口と出口の数が線形であることは想像に難くありません。in-k


3. テンプレートコード

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int, int> PII;
#define pb(s) push_back(s);
#define SZ(s) ((int)s.size());
#define ms(s,x) memset(s, x, sizeof(s))
#define all(s) s.begin(),s.end()
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const int N = 500010;

int n, k;
int pre[N], ne[N];
LL cnt[N];
void solve()
{
    
    
	cin >> n >> k;
	priority_queue<pair<LL, int>, vector<pair<LL, int>>, greater<pair<LL, int>> >q;
	for (int i = 1; i <= n; ++i) {
    
    
		LL v;
		cin >> v;
		q.push({
    
    v, i});
		pre[i] = i - 1;
		ne[i] = i + 1;
	}
	int g = n - k;
	while (q.size() > g) {
    
    
		auto p = q.top(); q.pop();
		LL v = p.first, ix = p.second;
		if (cnt[ix]) {
    
    
			q.push({
    
    v + cnt[ix], ix});
			cnt[ix] = 0;
		} else {
    
    
			int l = pre[ix], r = ne[ix];
			cnt[l] += v;
			cnt[r] += v;
			ne[l] = r;
			pre[r] = l;
		}
	}
	std::vector<LL> a(n + 1);
	for (int i = 0; i < g; ++i) {
    
    
		auto p = q.top(); q.pop();
		a[p.second] = p.first + cnt[p.second];
	}
	for (int i = 1; i <= n; ++i) {
    
    
		if (a[i]) cout << a[i] << " ";
	}
}
int main()
{
    
    
	ios_base :: sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	int t = 1;
	while (t--)
	{
    
    
		solve();
	}
	return 0;
}

質問 I. シーニック・ツーリズム

1. トピックの説明

   風光明媚な場所には合計NNがあります1 1の番号が付けられたN個のアトラクション1NNN._ _ アトラクションにはN − 1 N − 1N双方向のシャトルバス路線がツリー構造で接続されています景勝地間の移動はシャトルバスのみで、ある程度の時間がかかります。
   Xiao Ming はこの景勝地のシニア ツアー ガイドで、毎日一定の順序でKKKアトラクション:A 1 、A 2 、…、AK A_1、A_2、…、A_K12... ,K. 今日、時間の制約により、Xiao Ming は景勝地の 1 つをスキップし、観光客だけを順番にK − 1 K − 1に連れて行くことにしました。K1アトラクション。具体的には、Xiao Ming がA i A_i,那么他会按顺序带游客游览 A 1 , A 2 , . . . , A i − 1 , A i + 1 , . . . , A K , ( 1 ≤ i ≤ K ) A_1, A_2, . . . , A_{i−1}, A_{i+1}, . . . , A_K, (1 ≤ i ≤ K) 12... ,i 1i + 1... ,K( 1K AiAi
   について教えてくださいA i , Xiao Ming がこのアトラクションをスキップした場合、アトラクション間のシャトルバスに費やす必要がある時間を計算してください?

2. 問題解決のアイデア

   LCA LCAL C Aテンプレートの質問 (問題は、競技者がボードに書き込めないことです) では、まず、ツリー上の任意の 2 点間の距離を見つけることを検討する必要があります。セットポイントu , vu,vあなたvの最も近い共通の祖先zzz、定義f [ i ] f[i]f[i] 为点 i i iをルート ノードに移動すると、式があります:
dist ( u , v ) = f [ u ] + f [ v ] − 2 ∗ f [ z ] dist(u,v)=f[u]+f[v ]-2*f[z]d i s t ( u ,v )=f [ u ]+f [ v ]2f [ z ]
   最初に、ポイントをスキップしない場合に歩く必要がある距離ansと、隣接する 2 つのジャンプ ポイント間の距離を計算します。a 、 b 、 c 、 da、b、c、d の4 つのポイントをスキップするとします。_b c d . スキップポイントがaaa 、 aaans減算するだけですaからbbスキップされたポイントがddの場合のbの距離d 、 cc をans引くだけですcからdddの距離、これは最初と最後の 2 点の場合です。
   では、スキップされたポイントが中間ポイントである場合はどうなるでしょうか。たとえば、スキップするのはbbb、次にaaansを減算するaからbbbbbbからcccの距離、またaaaからccc、残りの中間点は同じ方法で処理されます。

3. テンプレートコード

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int, int> PII;
#define pb(s) push_back(s);
#define SZ(s) ((int)s.size());
#define ms(s,x) memset(s, x, sizeof(s))
#define all(s) s.begin(),s.end()
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const int N = 200010;

int n, m;
std::vector<PII> e[N];
int depth[N], fa[N][32];
LL f[N];
int root;
void bfs(int root)
{
    
    
	memset(depth, 0x3f, sizeof depth);
	depth[0] = 0, depth[root] = 1;
	queue<int> q;
	q.push(root);
	while (!q.empty()) {
    
    
		auto t = q.front();
		q.pop();
		for (auto [j, c] : e[t]) {
    
    
			if (depth[j] > depth[t] + 1) {
    
    
				depth[j] = depth[t] + 1;
				q.push(j);
				fa[j][0] = t;
				for (int k = 1; k <= 15; k++) {
    
    
					fa[j][k] = fa[fa[j][k - 1]][k - 1];
				}
			}
		}
	}
}
void dfs(int u, int fa) {
    
    
	for (auto [v, c] : e[u]) {
    
    
		if (v == fa) continue;
		f[v] = f[u] + c;
		dfs(v, u);
	}
}
int lca(int a, int b) {
    
    
	if (depth[a] < depth[b]) swap(a, b);
	for (int k = 15; k >= 0; k--) {
    
    
		if (depth[fa[a][k]] >= depth[b]) {
    
    
			a = fa[a][k];
		}
	}
	if (a == b) return a;
	for (int k = 15; k >= 0; --k) {
    
    
		if (fa[a][k] != fa[b][k]) {
    
    
			a = fa[a][k];
			b = fa[b][k];
		}
	}
	return fa[a][0];
}
void solve()
{
    
    
	cin >> n >> m;
	for (int i = 0; i < n - 1; ++i) {
    
    
		int u, v , c;
		cin >> u >> v >> c;
		e[u].push_back({
    
    v, c});
		e[v].push_back({
    
    u, c});
	}
	bfs(1);
	dfs(1, -1);
	std::vector<LL> g(m + 1), w(m + 1);
	for (int i = 1; i <= m; ++i) cin >> g[i];
	LL ans = 0;
	for (int i = 1; i < m; ++i) {
    
    
		int u = g[i], v = g[i + 1];
		int z = lca(u, v);
		w[i] = f[u] + f[v] - 2 * f[z];
		ans += w[i];
	}
	for (int i = 1; i <= m; ++i) {
    
    
		if (i == 1) cout << ans - w[1] << " ";
		else if (i == m) cout << ans - w[m - 1] << " ";
		else {
    
    
			LL res = ans - w[i] - w[i - 1];
			int u = g[i - 1], v = g[i + 1];
			int z = lca(u, v);
			res += f[u] + f[v] - 2 * f[z];
			cout << res << " ";
		}
	}
}
int main()
{
    
    
	ios_base :: sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	int t = 1;
	while (t--)
	{
    
    
		solve();
	}
	return 0;
}

質問 J. 木を切る

1. トピックの説明

nn   によって与えられた木n個のノードとmmm 個の繰り返さない乱数のペア( a 1 , b 1 ) , ( a 2 , b 2 ) , . . , ( am , bm ) (a1, b1), (a_2, b_2), . . , ( a_m 、b_m)( a 1 ,b 1 ) ,( _2b2) ... ,( _メートルbメートル),其中 a i ai aiは互いに異なる、bi b_ib互いに異なるai , bj ( 1 ≤ i , j ≤ m ) a_i , b_j(1 ≤ i, j ≤ m)ab( 1私はjm ) .
   Xiao Ming は、伐採する木の端を選択できるかどうかを知りたがっています。それぞれ( ai , bi ) (ai , bi)あいbi) 满足 a i ai ai b i bi biが接続されていない場合、可能であれば、壊すべきエッジの番号を出力します (番号は、1 から 1 まで1 )、そうでなければ出力- 1 -1−1 _

2. 問題解決のアイデア

LCA LCA   再びL Cひな形の質問ですが、やったことはありません (LCA LCALC A ) . ポイントxxの順序付けられていないペアのペアを考えてみましょうxyyy、エッジを切り取ってこれらの 2 点を切断する場合、このエッジはxxx〜yy __xxから作成できるyパス上の点x〜yy __yパスのエッジ ウェイト1この操作にはツリー差分を使用できますミリm 個の順序付けられていない数はこのように機能し、最終的に特定のエッジの重みがmmmは条件を満たしていることを意味し、条件を満たしている数字が大きい側を答えとして、重りがない場合はmmmのエッジは解がないことを意味します。

3. テンプレートコード

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int, int> PII;
#define pb(s) push_back(s);
#define SZ(s) ((int)s.size());
#define ms(s,x) memset(s, x, sizeof(s))
#define all(s) s.begin(),s.end()
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const int N = 200010;

int n, m;
std::vector<int> e[N];
int depth[N], fa[N][32];
int f[N];
int root;
int ans;
map<PII, int> mp;
void bfs(int root)
{
    
    
	ms(depth, 0x3f);
	depth[0] = 0, depth[root] = 1;
	queue<int> q;
	q.push(root);
	while (!q.empty()) {
    
    
		auto t = q.front();
		q.pop();
		for (int j : e[t]) {
    
    
			if (depth[j] > depth[t] + 1) {
    
    
				depth[j] = depth[t] + 1;
				q.push(j);
				fa[j][0] = t;
				for (int k = 1; k <= 15; 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 = 15; k >= 0; k--) {
    
    
		if (depth[fa[a][k]] >= depth[b]) {
    
    
			a = fa[a][k];
		}
	}
	if (a == b) return a;
	for (int k = 15; 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 fa) {
    
    
	int res = f[u];
	for (auto v : e[u]) {
    
    
		if (v == fa) continue;
		int g = dfs(v, u);
		if (g == m) {
    
    
			ans = max(ans, mp[ {
    
    v, u}]);
		}
		res += g;
	}
	return res;
}
void solve()
{
    
    
	cin >> n >> m;
	for (int i = 0; i < n - 1; ++i) {
    
    
		int u, v;
		cin >> u >> v;
		mp[ {
    
    u, v}] = mp[ {
    
    v, u}] = i + 1;
		e[u].push_back(v);
		e[v].push_back(u);
	}
	bfs(1);
	for (int i = 0; i < m; ++i) {
    
    
		int u, v;
		cin >> u >> v;
		int z = lca(u, v);
		f[u]++;
		f[v]++;
		f[z] -= 2;
	}
	dfs(1, -1);
	cout << (ans == 0 ? -1 : ans) << '\n';
}
int main()
{
    
    
	ios_base :: sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	int t = 1;
	while (t--)
	{
    
    
		solve();
	}
	return 0;
}

おすすめ

転載: blog.csdn.net/m0_57487901/article/details/130036113