Codeforces Round 991 div3 個人題解(A~G)

ExtractStars發表於2024-12-06

Codeforces Round 991 div3 個人題解(A~G)

Dashboard - Codeforces Round 991 (Div. 3) - Codeforces

A. Line Breaks

科斯佳有一個由 \(n\) 個拉丁字母組成的文字 \(s\)。他還必須在兩張紙條上書寫文字。第一張紙條可以容納 \(m\) 個字元,而第二張紙條可以容納儘可能多的字元。

科斯佳必須選擇一個數字 \(x\),並在第一條上寫下 \(s\) 中的第一個 \(x\) 字,而其餘所有字都寫在第二條上。為了節省空間,單詞的書寫不留空隙,但每個單詞必須完全寫在一張紙條上。

由於第二條上的空間非常寶貴,科斯佳要求你選擇最大可能的數字 \(x\),使所有單詞 \(s_1, s_2, \ldots, s_x\) 都能寫在長度為 \(m\) 的第一條上。

輸入
第一行包含一個整數 \(t\) \((1 \leq t \leq 1000)\) — 測試用例的數量。

每個測試用例的第一行包含兩個整數 \(n\)\(m\) \((1 \leq n \leq 50; 1 \leq m \leq 500)\) — 列表中的單詞數量和第一條紙條上可以放置的最大字元數。

接下來的 \(n\) 行包含一個單詞 \(s_i\)(由小寫拉丁字母組成),其中 \(s_i\) 的長度不超過 \(10\)

輸出
對於每個測試用例,輸出最大字數 \(x\),使得前 \(x\) 個字的總長度不超過 \(m\)

示例
輸入

5
3 1
a
b
c
2 9
alpha
beta
4 12
hello
world
and
codeforces
3 2
ab
c
d
3 2
abc
ab
a

輸出

1
2
2
1
0

解題思路

按照題目意思模擬,累加字串長度直到大於 \(m\) 即可。

題解程式碼

#include <bits/stdc++.h>

using namespace std;

using ll = long long;
using ld = long double;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using vi = vector<int>;
using vl = vector<ll>;

#define inf 0x3f3f3f3f
#define infll 0x3f3f3f3f3f3f3f3fLL
void solve()
{
    int n, m;
    cin >> n >> m;
    int sum = 0;
    vector<string> v(n);
    for (int i = 0; i < n; i++)
    {
        cin >> v[i];
    }
    for (int i = 0; i < n; i++)
    {
        if (sum + v[i].length() <= m)
        {
            sum += v[i].length();
        }
        else
        {
            cout << i << "\n";
            return;
        }
    }
    cout << n << "\n";
}

int main()
{
    ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
    // freopen("test.in", "r", stdin);
    // freopen("test.out", "w", stdout);
    int _ = 1;
    std::cin >> _;
    while (_--)
    {
        solve();
    }
    return 0;
}

/*######################################END######################################*/
// 連結:

B. Transfusion

給你一個長度為 \(n\) 的陣列 \(a\)。在一次操作中,你可以從 \(2\)\(n-1\)(含)之間選取索引 \(i\),並執行以下操作之一:

  • \(a_{i-1}\) 減少 \(1\),然後將 \(a_{i+1}\) 增加 \(1\)
  • \(a_{i+1}\) 減少 \(1\),然後將 \(a_{i-1}\) 增加 \(1\)

每次運算後,所有數值都必須為非負。你能在任意多次運算後使所有元素相等嗎?

輸入
第一行輸入包括一個整數 \(t\) \((1 \leq t \leq 10^4)\) - 測試用例數。

每個測試用例的第一行由一個整數 \(n\) \((3 \leq n \leq 2 \cdot 10^5)\) 組成。

每個測試用例的第二行由 \(n\) 個整數 \(a_i\) \((1 \leq a_i \leq 10^9)\) 組成。

保證所有測試用例的 \(n\) 之和不超過 \(2 \cdot 10^5\)

輸出
對於每個測試用例,如果經過任意次數的運算後可以使所有元素相等,則列印 "YES"(不帶引號);否則,列印 "NO"(不帶引號)。

您可以用任何暫存器列印答案:"yes"、"YeS"、"nO" - 也會被認為是正確的。

示例
輸入

8
3
3 2 1
3
1 1 3
4
1 2 5 4
4
1 6 6 1
5
6 2 1 4 2
4
1 4 2 1
5
3 1 2 1 3
3
2 4 2

輸出

YES
NO
YES
NO
YES
NO
NO
NO

解題思路

我們只能同時操作奇數或偶數下標,且+1 -1不改變總值,因此將所有間隔為 \(1\) 的值相加,檢查它們之和是否為數量的倍數且平均數相等即可。

題解程式碼

#include <bits/stdc++.h>

using namespace std;

using ll = long long;
using ld = long double;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using vi = vector<int>;
using vl = vector<ll>;

#define inf 0x3f3f3f3f
#define infll 0x3f3f3f3f3f3f3f3fLL
void solve()
{
    int n;
    cin >> n;
    vl a(n);
    ll sum1 = 0;
    ll sum2 = 0;
    ll cnt1 = 0;
    ll cnt2 = 0;
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
        if (i & 1)
            sum1 += a[i], cnt1++;
        else
            sum2 += a[i], cnt2++;
    }
    if (n == 1)
    {
        cout << "YES\n";
    }
    if (sum1 % cnt1 || sum2 % cnt2 || sum1 / cnt1 != sum2 / cnt2)
    {
        cout << "NO\n";
    }
    else
    {
        cout << "YES\n";
    }
}

int main()
{
    ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
    // freopen("test.in", "r", stdin);
    // freopen("test.out", "w", stdout);
    int _ = 1;
    std::cin >> _;
    while (_--)
    {
        solve();
    }
    return 0;
}

/*######################################END######################################*/
// 連結:

C. Uninteresting Number

給你一個長度不超過 \(10^5\) 的數字 \(n\)

你可以多次進行下面的運算:選擇其中一位數字,將其平方,然後用運算結果替換原來的數字。結果必須是一位數字(也就是說,如果您選擇數字 \(x\),那麼 \(x^2\) 的值必須小於 \(10\))。

透過這些運算,有可能得到一個能被 \(9\) 整除的數嗎?

輸入
第一行包含一個整數 \(t\) \((1 \leq t \leq 10^4)\) - 測試用例的數量。

每個測試用例的唯一一行包含數字 \(n\),不含前導零。數字長度不超過 \(10^5\)

保證所有測試用例的數字長度之和不超過 \(10^5\)

輸出
對於每個測試用例,如果可以透過所述操作得到一個能被 \(9\) 整除的數,則輸出 "YES",否則輸出 "NO"。

您可以以任何大小寫(小寫或大寫)輸出每個字母。例如,字串 "yEs"、"yes"、"Yes" 和 "YES" 將被視為肯定答案。

示例
輸入

9
123
322
333333333333
9997
5472778912773
1234567890
23
33
52254522632

輸出

NO
YES
YES
NO
NO
YES
NO
YES
YES

注意
在第一個示例中,從整數 \(123\),只能得到 \(123\)\(143\)\(129\)\(149\),其中沒有一個能被 \(9\) 整除。

在第二個示例中,你需要將第二個數字替換為它的平方;然後 \(n\) 將等於 \(342=38 \cdot 9\)

在第三個示例中,整數已經能被 \(9\) 整除。

解題思路

由小學數學知識可知 \(9\) 的倍數的各數位之和也為 \(9\) 的倍數。觀察發現,只有 \(2\)\(3\) 平方後會對數位之後有影響。

因此,我們統計一下 \(2\)\(3\) 的數量,然計算一下數位之和,算出它與最近的 \(9\) 的倍數的差值 \(r\) ,如果 \(r\) 為奇數的話我們記得要 加 \(9\) ,因為我們不管是給 \(2\) 平方 還是給 \(3\) 平方都只能對數位和增加偶數。

然後優先給 \(3\) 平方,看剩下的值是否能用 \(2\) 平方湊出來即可。

題解程式碼

#include <bits/stdc++.h>

using namespace std;

using ll = long long;
using ld = long double;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using vi = vector<int>;
using vl = vector<ll>;

#define inf 0x3f3f3f3f
#define infll 0x3f3f3f3f3f3f3f3fLL
void solve()
{
    string s;
    cin >> s;
    int cnt2 = 0;
    int cnt3 = 0;
    int sum = 0;
    for (auto c : s)
    {
        if (c == '2')
            cnt2++;
        else if (c == '3')
            cnt3++;
        sum += (c - '0');
    }
    int r = (9 - sum % 9);
    if (r == 9)
    {
        cout << "YES" << "\n";
        return;
    }
    // cout << sum << "\n";
    if (r & 1)
        r += 9;
    r -= min(cnt3, (r / 6)) * 6;
    // cout << r << "\n";
    int need = r / 2;
    if (cnt2 >= need)
        cout << "YES" << "\n";
    else
        cout << "NO" << "\n";
}
int main()
{
    ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
    // freopen("test.in", "r", stdin);
    // freopen("test.out", "w", stdout);
    int _ = 1;
    std::cin >> _;
    while (_--)
    {
        solve();
    }
    return 0;
}

/*######################################END######################################*/
// 連結:

D. Digital string maximization

給你一個字串 \(s\),由從 \(0\)\(9\) 的數字組成。在一次運算中,您可以選取該字串中除 \(0\) 或最左邊數字之外的任意一個數字,將其減少 \(1\),然後將其與左邊的數字對調。

例如,從字串 \(1023\) 中進行一次運算,可以得到 \(1103\)\(1022\)

找出任意多次運算後可以得到的詞序最大字串。

輸入
輸入的第一行是一個整數 \(t\) \((1 \leq t \leq 10^4)\) - 測試用例的數量。

每個測試用例由一行數字字串 \(s\) \((1 \leq |s| \leq 2 \cdot 10^5)\) 組成,其中 \(|s|\) 表示 \(s\) 的長度。

保證所有測試用例的 \(|s|\) 之和不超過 \(2 \cdot 10^5\)

輸出
對於每個測試用例,在單獨的一行中列印答案。

示例
輸入

6
19
1709
11555
51476
9876543210
5891917899

輸出

81
6710
33311
55431
9876543210
7875567711

注意
在第一個示例中,以下操作序列是合適的:\(19 \rightarrow 81\)

在第二個示例中,以下操作序列是合適的:\(1709 \rightarrow 1780 \rightarrow 6180 \rightarrow 6710\)

在第四個示例中,以下操作序列是合適的:\(51476 \rightarrow 53176 \rightarrow 53616 \rightarrow 53651 \rightarrow 55351 \rightarrow 55431\)

解題思路

由於題目限定了所有測試用例的 \(|s|\) 之和不超過 \(2 \cdot 10^5\) ,因此我們直接對每一位數進行模擬,向後找10位,貪心的把換過來最大的數換過來即可,時間複雜度為 \(20n\)

題解程式碼

#include <bits/stdc++.h>

using namespace std;

using ll = long long;
using ld = long double;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using vi = vector<int>;
using vl = vector<ll>;

#define inf 0x3f3f3f3f
#define infll 0x3f3f3f3f3f3f3f3fLL
void solve()
{
    string s;
    cin >> s;
    int n = s.size();
    for (int i = 0; i < n; i++)
    {
        string t = s.substr(i, min(10, n - i));
        int mx = s[i] - '0';
        int pos = 0;
        for (int j = 0; j < t.size(); j++)
        {
            if (t[j] - '0' - j > mx)
            {
                mx = t[j] - '0' - j;
                pos = j;
            }
        }
        s[i] = mx + '0';
        for (int j = 0, k = 1; j < t.size(), k < t.size(); j++)
        {
            if (j == pos)
                continue;
            s[i + k] = t[j];
            k++;
        }
    }
    cout << s << "\n";
}

int main()
{
    ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
    // freopen("test.in", "r", stdin);
    // freopen("test.out", "w", stdout);
    int _ = 1;
    std::cin >> _;
    while (_--)
    {
        solve();
    }
    return 0;
}

/*######################################END######################################*/
// 連結:

E. Three Strings

給您三個字串:\(a\)\(b\)\(c\),由小寫拉丁字母組成。字串 \(c\) 是透過以下方法得到的:

每一步都隨機選擇字串 \(a\) 或字串 \(b\),並將所選字串的第一個字元從中刪除,然後新增到字串 \(c\) 的末尾,直到其中一個字串用完為止。之後,將非空字串的剩餘字元新增到 \(c\) 的末尾。然後,隨機更改字串 \(c\) 中的一定數量字元。

例如,從字串 \(a=\text{abra}\)\(b=\text{cada}\) 中,在不替換字元的情況下,可以得到字串 \(\text{caabdraa}\)\(\text{abracada}\)\(\text{acadabra}\)

求字串 \(c\) 中最少可以替換的字元數。

輸入
輸入的第一行包含一個整數 \(t\) \((1 \leq t \leq 10^3)\) - 測試用例的數量。

每個測試用例的第一行包含一個拉丁字母小寫字串 \(a\) \((1 \leq |a| \leq 10^3)\) - 第一個字串,其中 \(|a|\) 表示字串 \(a\) 的長度。

每個測試用例的第二行包含一個小寫拉丁字母字串 \(b\) \((1 \leq |b| \leq 10^3)\) - 第二字串,其中 \(|b|\) 表示字串 \(b\) 的長度。

每個測試用例的第三行包含一串拉丁小寫字母 \(c\) \((|c|=|a|+|b|)\) - 第三字串。

保證所有測試用例中 \(|a|\) 的總和不超過 \(2 \cdot 10^3\)。同時,所有測試用例中 \(|b|\) 的總和不超過 \(2 \cdot 10^3\)

輸出
針對每個測試用例,輸出一個整數 - 字串 \(c\) 中可能被更改的最少字元數。

示例
輸入

7
a
b
cb
ab
cd
acbd
ab
ba
aabb
xxx
yyy
xyxyxy
a
bcd
decf
codes
horse
codeforces
egg
annie
egaegaeg

輸出

1
0
2
0
3
2
3
15

解題思路

定義 \(dp[i][j]\) 表示使用 \(a\) 的前 \(i\) 個字元和 \(b\) 的前 \(j\) 個字元合並後,與 \(c\) 的前 \(i+j\) 個字元匹配所需的最小修改次數。

如果我們選擇從 \(a\) 中取出第 \(i\) 個字元,那麼:

\(dp[i][j] = dp[i-1][j] + (a[i-1] != c[i+j-1])\)

如果選擇從 \(b\) 中取出第 \(j\) 個字元,那麼:

\(dp[i][j] = dp[i][j-1] + (b[j-1] != c[i+j-1])\)

因此狀態轉移方程為:

\[dp[i][j] = \min(dp[i-1][j] + (a[i-1] != c[i+j-1]) , dp[i][j-1] + (b[j-1] != c[i+j-1])) \]

題解程式碼

#include <bits/stdc++.h>

using namespace std;

using ll = long long;
using ld = long double;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using vi = vector<int>;
using vl = vector<ll>;

#define inf 0x3f3f3f3f
#define infll 0x3f3f3f3f3f3f3f3fLL
void solve()
{
    string a, b, c;
    cin >> a >> b >> c;
    int na = a.size();
    int nb = b.size();
    vi f(nb + 1);
    for (int j = 1; j <= nb; j++)
    {
        f[j] = f[j - 1] + (b[j - 1] != c[j - 1]);
    }
    for (int i = 1; i <= na; i++)
    {
        vi g(nb + 1);
        g[0] = f[0] + (a[i - 1] != c[i - 1]);
        for (int j = 1; j <= nb; j++)
        {
            int idx = i + j - 1;
            int costA = f[j] + (a[i - 1] != c[idx]);
            int costB = g[j - 1] + (b[j - 1] != c[idx]);
            g[j] = min(costA, costB);
        }
        f.swap(g);
    }
    cout << f[nb] << "\n";
}

int main()
{
    ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
    // freopen("test.in", "r", stdin);
    // freopen("test.out", "w", stdout);
    int _ = 1;
    std::cin >> _;
    while (_--)
    {
        solve();
    }
    return 0;
}

/*######################################END######################################*/
// 連結:

F. Maximum modulo equality

給你一個長度為 \(n\) 的陣列 \(a\)\(q\) 查詢 \(l, r\)

對於每個查詢,找出最大可能的 \(m\),使得所有元素 \(a_l, a_{l+1}, \ldots, a_r\) 都等於模 \(m\)。換句話說,\(a_l \mod m = a_{l+1} \mod m = \cdots = a_r \mod m\),其中 \(a \mod b\)\(a\) 除以 \(b\) 的餘數。特別是當 \(m\) 可以是無限時,列印 \(0\)

輸入
第一行包含一個整數 \(t\) \((1 \leq t \leq 10^4)\) - 測試用例數。

每個測試用例的第一行包含兩個整數 \(n, q\) \((1 \leq n, q \leq 2 \cdot 10^5)\) - 陣列長度和查詢次數。

每個測試用例的第二行包含 \(n\) 個整數 \(a_i\) \((1 \leq a_i \leq 10^9)\) - 陣列的元素。

在每個測試用例的後續 \(q\) 行中,提供了兩個整數 \(l, r\) \((1 \leq l \leq r \leq n)\) - 查詢範圍。

保證所有測試用例中 \(n\) 的總和不超過 \(2 \cdot 10^5\)\(q\) 的總和不超過 \(2 \cdot 10^5\)

輸出
對於每個查詢,輸出語句中描述的最大值 \(m\)

示例
輸入

3
5 5
5 14 2 6 3
4 5
1 4
2 4
3 5
1 1
1 1
7
1 1
3 2
1 7 8
2 3
1 2

輸出

3 1 4 1 0 
0 
1 6 

注意
在第一個示例的第一個查詢中,\(6 \mod 3 = 3 \mod 3 = 0\)。可以證明對於更大的 \(m\),所需條件將不成立。

在第一個示例的第三個查詢中,\(14 \mod 4 = 2 \mod 4 = 6 \mod 4 = 2\)。可以證明對於更大的 \(m\),所需條件將不成立。

解題思路

對於每個查詢區間 \([l, r]\) ,我們需要找到最大的 \(m\),滿足條件:\(a_l \mod m = a_{l+1} \mod m = \cdots = a_r \mod m\)

根據同餘的性質,若所有元素對 \(m\) 取餘相同,則任意兩個元素的差都能被 \(m\) 整除。因此,\(m\) 必須是區間內所有元素兩兩差值的最大公約數 \(\text{GCD}\)。即

\[m = \text{GCD}(a_{l+1} - a_l, a_{l+2} - a_l, \dots, a_r - a_l) \]

因此,我們先計算出可以 \(a\) 的差分陣列,然後使用ST表或者線段樹維護區間GCD即可

題解程式碼

#include <bits/stdc++.h>

using namespace std;

using ll = long long;
using ld = long double;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using vi = vector<int>;
using vl = vector<ll>;

#define inf 0x3f3f3f3f
#define infll 0x3f3f3f3f3f3f3f3fLL

const int N = 2e5 + 5;
const int LGN = 20;

int LOG2[N];
void getLog()
{
    LOG2[1] = 0;
    for (int i = 2; i < N; i++)
    {
        LOG2[i] = LOG2[i / 2] + 1;
    }
}
void solve()
{
    int n, q;
    cin >> n >> q;
    vl a(n);
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
    }

    int m = n - 1;
    vl d(m);
    for (int i = 0; i < m; i++)
    {
        d[i] = abs(a[i + 1] - a[i]);
    }

    vector<vl> st;
    int K = 0;
    if (m > 0)
    {
        K = LOG2[m] + 1;
        st.assign(m, vl(K));
        for (int i = 0; i < m; i++)
        {
            st[i][0] = d[i];
        }
        for (int j = 1; j < K; j++)
        {
            for (int i = 0; i + (1 << j) <= m; i++)
            {
                st[i][j] = gcd(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
            }
        }
    }
    vl ans;
    while (q--)
    {
        int l, r;
        cin >> l >> r;
        if (l == r)
        {
            ans.push_back(0);
            continue;
        }
        int L = l - 1;
        int R = r - 2;
        int length = R - L + 1;
        int k = LOG2[length];
        ll res = gcd(st[L][k], st[R - (1 << k) + 1][k]);
        ans.push_back(res == 0 ? 0 : res);
    }
    for (int i = 0; i < ans.size(); i++)
    {
        cout << ans[i] << " ";
    }
    cout << "\n";
}

int main()
{
    ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
    // freopen("test.in", "r", stdin);
    // freopen("test.out", "w", stdout);
    int _ = 1;
    std::cin >> _;
    getLog();
    while (_--)
    {
        solve();
    }
    return 0;
}

/*######################################END######################################*/
// 連結:

G. Tree Destruction

給定一棵有 \(n\) 個頂點的樹∗。您可以選擇兩個頂點 \(a\)\(b\) 一次,然後刪除從 \(a\)\(b\) 的路徑上的所有頂點,包括頂點本身。如果您選擇 \(a=b\),則只會刪除一個頂點。

你的任務是找出從樹中移除路徑後所能形成的最大連通元件數†。

∗ 樹是一個沒有迴圈的連通圖。

† 一個連通部分是這樣一個頂點集合:從任意頂點到集合中的任意其他頂點都有一條沿著邊的路徑(並且不可能到達不屬於這個集合的頂點)。

輸入
輸入的第一行包含一個整數 \(t\) \((1 \leq t \leq 10^4)\) - 測試用例的數量。

每個測試用例的第一行包含一個整數 \(n\) \((2 \leq n \leq 2 \cdot 10^5)\) - 樹的大小。

接下來的 \(n-1\) 行包含兩個整數 \(u\)\(v\) \((1 \leq u, v \leq n, u \neq v)\) - 由一條邊連線的頂點。可以保證這些邊構成一棵樹。

保證所有測試用例中 \(n\) 的總和不超過 \(2 \cdot 10^5\)

輸出
對於每個測試用例,輸出一個整數 - 使用所述操作可實現的最大連線元件數。

示例
輸入

6
2
1 2
5
1 2
2 3
3 4
3 5
4
1 2
2 3
3 4
5
2 1
3 1
4 1
5 4
6
2 1
3 1
4 1
5 3
6 3
6
2 1
3 2
4 2
5 3
6 4

輸出

1
3
2
3
4
3

解題思路

觀察發現,移除路徑上的每個節點會斷開其附屬的子樹。

因此我們需要選擇一條路徑,使得路徑上的節點具有儘可能多的子樹,從而最大化移除後形成的連通分量數量。

簡單模擬可得

  • 對於路徑上的每個節點,其貢獻的連通分量數量為 \(deg[u] - 2\),其中 \(deg[u]\) 是節點的度數。

  • 對於路徑的端點,貢獻為 \(deg[u] - 1\)

因此,目標轉化為在樹中找到一條路徑,使得路徑上所有節點的 \(deg[u] - 2\) 之和最大。最終的連通分量數量為這個和加上2。

我們可以使用DFS遍歷樹,計算每條路徑的 \(deg[u] - 2)\) 之和。

題解程式碼

#include <bits/stdc++.h>

using namespace std;

using ll = long long;
using ld = long double;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using vi = vector<int>;
using vl = vector<ll>;

#define inf 0x3f3f3f3f
#define infll 0x3f3f3f3f3f3f3f3fLL
void solve()
{
    int n;
    cin >> n;
    vector<vi> adj(n + 1);
    vi deg(n + 1, 0);
    for (int i = 1; i < n; i++)
    {
        int u, v;
        cin >> u >> v;
        adj[u].push_back(v);
        adj[v].push_back(u);
        deg[u]++;
        deg[v]++;
    }
    vl val(n + 1);
    for (int i = 1; i <= n; i++)
    {
        val[i] = deg[i] - 2;
    }
    ll ans = -infll;
    auto dfs = [&](auto &self, int u, int fa) -> ll
    {
        vl sums;
        for (auto &v : adj[u])
        {
            if (v == fa)
                continue;
            ll sum = self(self, v, u);
            if (sum > 0)
                sums.push_back(sum);
        }
        sort(sums.begin(), sums.end(), greater<ll>());
        ll now = val[u];
        if (!sums.empty())
            now += sums[0];
        ll tot = val[u];
        if (sums.size() >= 2)
            tot += sums[0] + sums[1];
        else if (sums.size() == 1)
            tot += sums[0];
        ans = max(ans, tot);
        ans = max(ans, now);
        return now;
    };
    dfs(dfs, 1, 0);
    ll res = ans + 2;
    cout << res << "\n";
}

int main()
{
    ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
    // freopen("test.in", "r", stdin);
    // freopen("test.out", "w", stdout);
    int _ = 1;
    std::cin >> _;
    while (_--)
    {
        solve();
    }
    return 0;
}

/*######################################END######################################*/
// 連結:

這場題目好典啊,感覺比平常d3簡單半個檔次

封面畫師id:竜崎いち - pixiv

相關文章