---
# System prepended metadata

title: 2024/5/25 APCS 第五場模擬賽 題解
tags: [題解]

---

# 2024/5/25 APCS 第五場模擬賽 題解
## 磁鐵 (Magnet)

> 出題者：ysh
> 難度：p1
> 考點：implemention

[官解](https://hackmd.io/@mysh212/H1FMfv1VR)

[真正的官解程式碼](https://judge.citrc.tw/status/c2ea2723f3244bbe190ff47f3edb9eff)

### Statement

***Amberela*** 打算使用好多磁鐵排出 $x$ ，你可以幫他算算總共需要幾條磁鐵嗎？

以下依序紀錄排出 $[0,9]$ 所需的磁鐵數量:

```
[6,2,5,5,4,5,6,4,7,6]
```
![image](https://hackmd.io/_uploads/rJQvRDmVC.png)



### Input

輸入只有一個數字 $x$ ，代表 ***Amberela*** 想排的數字，

### Output

請輸出共需要多少磁鐵。

### Input Format

$x$

### Output Format

$Ans$

### Testcase
- Input 1
```
123
```
- Output 1
```
12
```
### Subtask
- Subtask 1 (50%) - $10^2 \leq x \leq (10^3 - 1)$
- Subtask 2 (50%) - ***As statement***
### Note

 - $0 \leq x \leq (10^9)$
 - $x$ 不會有前綴 $0$ 。

### Solution

### Code

- 滿分 by 橘子
```cpp=
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const vector<ll> a = {6,2,5,5,4,5,6,4,7,6};
int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    ll ans = 0;
    string s;
    cin >> s;
    for(char c : s) ans += a[c-'0'];
    cout << ans << "\n";
}
```
```java=
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int[] a = {6,2,5,5,4,5,6,4,7,6};
        int ans = 0;
        String s = scanner.next();
        for (int c : s.chars().toArray()){
            ans += a[c-'0'];
        }
        System.out.println(ans);
        scanner.close();
    }
}
```
```python=
print(sum([6,2,5,5,4,5,6,4,7,6][int(c)] for c in input()))
```
## 地震 (Earthquake)
> 出題者：硫代硫酸鈉🌸
> 難度：p2
> 考點：二維陣列、窮舉

### Statement
最近實在是有太多地震了!可是硫代硫酸鈉卻一次警報都沒有收到，實在讓他很害怕。

於是呢，硫代硫酸鈉自行定義了一種整數搖晃程度單位 $m$ :「SCPA度」，為了增加精確度，劃分數值由 $0$ 到 $50$ 級。他定義座標 $x$ 軸向下為正，$y$ 軸向右取正，0-base，也定義 2D 平面上任兩點 $(a,b)$、$(c,d)$ 的水平距離就是 $\vert a-c \vert+\vert b-d \vert$。

這個搖晃程度大小又剛好和離震央水平距離、個人的所在的高度 $h$ 有密切的關係，無論當地高度為多少，震央高度一定為 $0$，水平距離每多 $1$，搖晃程度就少 $1$ 級，但高度每加 $1$，搖晃程度會多 $1$ 級。例如震央的「SCPA度」是 $3$ 級，有一地點與它的水平距離是 $5$，高度是 $4$，當地加上高度的的影響就會是 $2$ 級，若最終SCPA度小於 $0$，皆以 $0$ 計算。若大於 $50$，皆以 $50$ 計算。 
![image](https://hackmd.io/_uploads/Sy2Y0w7E0.png)

因為「SCPA度」是硫代硫酸鈉定義的，並且他也有分享給他的好朋友們這個單位，所以只要一地震，他和他的好朋友們也都能立刻得知他們各自所在位置的「SCPA度」。硫代硫酸鈉想匯集這些資料後，推算出震央的座標和搖晃程度，並得知各個親戚居住地的搖晃程度，預警大家，你能幫他分析並回答他嗎?

### Input
輸入的第一行會包含四個正整數 $n$、$m$、$N$、$Q$，代表 $n * m$ 的地圖，$N$ 代表硫代硫酸鈉和他的好朋友總人數，$Q$ 代表他的親戚總人數。

接下來 $n$ 行中，每行有 $m$ 個數字，代表地圖各地的高度 $h_i$

再接下來 $N$ 行中，每行有 3 個數字 $x_i$、$y_i$、$m_i$，分別是座標的 $x$、$y$ 與當地搖晃程度 $m$。

最後 $Q$ 行中，每行有 $2$ 個數字 $x_i$、$y_i$，代表他親戚居住地的座標。

### Output
請輸出 $Q$ 行，每行輸出 $1$ 個整數，為親戚居住地的搖晃程度。

**資料範圍**
- $1 \leq n、m \leq 30$
- $3 \leq N \leq 50$
- $1 \leq Q \leq 50$
- $0 \leq h \leq 10$
- $0 \leq x、y \leq 29$
- 保證所有座標皆不重複，且恰只有一個合理的震央
- 震央產生的地震，SCPA度會界於 $1$ 到 $50$ 之間


### Testcase
- Input 1
```
4 5 4 2
0 3 2 5 1
4 2 0 3 4
1 4 0 1 3
2 5 1 2 4
1 2 3
0 2 4
1 3 5
2 1 5
0 3
3 1
```
- Output 1
```
6
5
```

- Input 2
```
7 9 10 5
0 4 7 6 1 2 10 3 8
6 5 3 3 1 0 0 6 8
3 0 7 2 0 3 9 6 8
8 7 10 2 3 2 9 7 5
3 6 1 3 2 5 10 10 9
6 9 1 9 1 10 1 9 0
4 0 9 7 1 1 0 10 2
1 8 0
3 1 8
2 0 4
2 4 0
3 6 5
3 8 0
2 5 0
1 7 0
6 0 9
0 2 4
1 4
3 2
5 5
4 4
0 0
```
- Output 2
```
0
10
9
1
0 
```
### Subtask
- Subtask 1 (50%) - 第一個座標為硫代硫酸鈉的所在地，剛好就是震央，且當地高度為0
- Subtask 2 (50%) - 無特殊限制
### Note
範例測資一說明：
去除高度的影響後，(1,2)的SCPA度為3、(0,2)為2、(1,3)為2、(2,1)為1
可得知震央在(1,2)，SCPA度為3
所求的(0,3)和(3,1)加上高度後的SCPA度分別為6和5

### Solution
- Subtask 1 : 直接讀入第一個座標、搖晃程度，再推算各地
- Subtask 2 : 窮舉每個地點，窮舉1~50的SCPA度，每檢查一個地點的一種SCPA度都要去檢查是否符合朋友的條件
### Code
- Subtask 1
```cpp=
#include<bits/stdc++.h>
using namespace std;
 
int n=0,m=0,N=0,Q=0;
int s[55][55]={};
int ansx=0,ansy=0,ansap=0;
 
struct point{
    int x=0;
    int y=0;
    int apcs=0;
 
    point(int inx,int iny,int inapcs){
        x=inx;
        y=iny;
        apcs=inapcs;
    }
};
 
int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(0);
 
    cin>>n>>m>>N>>Q;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            cin>>s[i][j];
        }
    }
 
    cin>>ansx>>ansy>>ansap;
    for(int i=1;i<N;i++){
        int tmpx=0,tmpy=0,tmpap=0;
        cin>>tmpx>>tmpy>>tmpap;
    }
 
    for(int q=0;q<Q;q++){
        int qx=0,qy=0;
        cin>>qx>>qy;
        int ans=max(0,min(50,ansap-abs(ansx-qx)-abs(ansy-qy)+s[qx][qy]));
        cout<<ans<<(q==Q-1?"":"\n");
    }
}
```

- Subtask 1+2
```cpp=
#include<bits/stdc++.h>
using namespace std;

int n=0,m=0,N=0,Q=0;
int s[55][55]={};
int ansx=0,ansy=0,ansap=0;

struct point{
    int x=0;
    int y=0;
    int apcs=0;

    point(int inx,int iny,int inapcs){
        x=inx;
        y=iny;
        apcs=inapcs;
    }
};

vector<point> G;

void solve();

int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(0);

    cin>>n>>m>>N>>Q;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            cin>>s[i][j];
        }
    }

    for(int i=0;i<N;i++){
        int tmpx=0,tmpy=0,tmpap=0;
        cin>>tmpx>>tmpy>>tmpap;
        point P=point(tmpx,tmpy,tmpap);
        G.push_back(P);
    }

    solve();

    for(int q=0;q<Q;q++){
        int qx=0,qy=0;
        cin>>qx>>qy;
        int ans=max(0,min(50,ansap-abs(ansx-qx)-abs(ansy-qy)+s[qx][qy]));
        cout<<ans<<(q==Q-1?"":"\n");
    }
}

void solve(){
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            for(int ap=1;ap<=50;ap++){
                for(int k=0;k<N;k++){
                    int sup=ap-abs(i-G[k].x)-abs(j-G[k].y)+s[G[k].x][G[k].y];
                    sup=max(0,min(50,sup));
                    if(sup!=G[k].apcs) break;
                    if(k==N-1){
                        ansx=i;
                        ansy=j;
                        ansap=ap;
                        return;
                    }
                }
            }
        }
    }
}
```
- 滿分 by 橘子
```cpp=
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
const ll big = 1e18;
int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    ll n,M,c,q;
    cin >> n >> M >> c >> q;
    vector<vector<ll>> h(n,vector<ll>(M));
    for(auto &o : h) for(ll &i : o) cin >> i;
    vector<ll> x(c),y(c),m(c);
    for(ll i = 0;i<c;i++) cin >> x[i] >> y[i] >> m[i];
    for(ll a = 0;a<n;a++){
        for(ll b = 0;b<M;b++){
            for(ll w = 1;w<=50;w++){
                ll ok = 1;
                for(ll i = 0;i<c;i++){
                    ll cal = w-abs(a-x[i])-abs(b-y[i])+h[x[i]][y[i]];
                    cal = min(max(0ll,cal),50ll);
                    if (cal!=m[i]) ok = 0;
                }
                if(ok){
                    while(q--){
                        ll u,v;
                        cin >> u >> v;
                        ll cal = w-abs(a-u)-abs(b-v)+h[u][v];
                        cal = min(max(0ll,cal),50ll);
                        cout << cal << "\n";
                    }
                    return 0;
                }
            }
        }
    }
}
```

```java=
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt(),M=scanner.nextInt(),c=scanner.nextInt(),q=scanner.nextInt();
        int[][] h = new int[n][M];
        for(int a = 0;a<n;a++){
            for(int b = 0;b<M;b++){
                h[a][b] = scanner.nextInt();
            }
        }
        int[] x = new int[c];
        int[] y = new int[c];
        int[] m = new int[c];
        for(int i = 0;i<c;i++){
            x[i] = scanner.nextInt();
            y[i] = scanner.nextInt();
            m[i] = scanner.nextInt();
        }
        for(int a = 0;a<n;a++){
            for(int b = 0;b<M;b++){
                for(int w = 1;w<=50;w++){
                    boolean ok = true;
                    for(int i = 0;i<c;i++){
                        int cal = w-Math.abs(a-x[i])-Math.abs(b-y[i])+h[x[i]][y[i]];
                        cal = Math.min(Math.max(0,cal),50);
                        if (cal!=m[i]) ok = false;
                    }
                    if(ok){
                        for (int i = 0; i < q; i++) {
                            int u = scanner.nextInt(),v = scanner.nextInt();
                            int cal = w-Math.abs(a-u)-Math.abs(b-v)+h[u][v];
                            cal = Math.min(Math.max(0,cal),50);
                            System.out.println(""+cal);
                        }
                        System.exit(0);
                    }
                }
            }
        }
        scanner.close();
    }
}
```

```python=
N,M,n,q = map(int,input().split())
h = [list(map(int,input().split())) for _ in range(N)]
l = [list(map(int,input().split())) for _ in range(n)]
for a in range(N):
    for b in range(M):
        for w in range(1,51):
            for x,y,m in l:
                cal = w-abs(a-x)-abs(b-y)+h[x][y]
                cal = min(max(0,cal),50)
                if cal != m:
                    break
            else:
                for _ in range(q):
                    x,y = map(int,input().split())
                    cal = w-abs(a-x)-abs(b-y)+h[x][y]
                    cal = min(max(0,cal),50)
                    print(cal)
                break
        else:
            continue
        break
    else:
        continue
    break
```

```python!
print(*(lambda N,M,n,q:(lambda h,l,qs:next((min(max(0,w-abs(a-x)-abs(b-y)+h[x][y]),50) for x,y in qs) for a in range(N) for b in range(M) for w in range(1,51) if all(m==min(max(0,w-abs(a-x)-abs(b-y)+h[x][y]),50) for x,y,m in l)))([list(map(int,input().split())) for _ in range(N)],[list(map(int,input().split())) for _ in range(n)],[list(map(int,input().split())) for _ in range(q)]))(*map(int,input().split())),sep="\n")

```
## 大智慧學苑-來上體育課吧 (PE class)
> 出題者：Howard
> 難度：p3
> 考點：二分搜
### Statement
在大智慧學苑中，為了讓小朋友平時可以動一動，於是有一個區塊是可以讓小朋友跳來跳去的地方，會有一些板子散落在一條直線上，小朋友可以站在這些板子上跳來跳去的，但是當初在建造大智慧學苑的時候，這些被誤認為是給1歲小孩使用的，於是，有些板子和板子之間的距離超級近，這讓大智慧學苑的小朋友覺得太簡單，身為大智慧學苑院長Chung要來解決這個問題，但他真的很懶，只想把 $k$ 個板子搬走，為了可以預測最好的辦法，請寫一個程式模擬，在可以搬走 $k$ 個板子的情況下，板子和板子最小的距離可以到多大。
在這個跳格子的場地當中，小朋友會從位置 0 的地方出發，終點則是在位置 $T$。
### Input
第一行有三個數字 $N、K、T$ 一開始板子的數量，Chung想移開板子的數量，以及終點位置，中間以空白間隔開。
第二行開始有 $N$ 個數字 $(a_1,a_2,a_3,...,a_n)$ 代表每個板子一開始放置的位置，中間以空白間隔開，保證已排序。
$1\leq k\leq N \leq 10^3$
$N+1\leq T\leq 10^9$
$1\leq a_1 < a_2 < a_3 < ... < a_n <T$
### Output
輸出一個數字，在可以搬走 $k$ 個板子的情況下，板子和板子最小的距離可以到多大。
### Input Format
$N\ K\ T$
$a_1 \space a_2 \space \dots \space a_n$
### Output Format
$ans$
### Testcase
- Input 1
```
6 2 20
1 7 12 15 17 19
```
- Output 1
```
2
```
### Subtask
- Subtask 1 (30%) - $1\leq k\leq N \leq 160、N+1\leq T\leq 2\times 10^3$
- Subtask 2 (70%) - $1\leq k\leq N \leq 10^3、N+1\leq T\leq 1\times 10^9$
### Note
在第一組測資中，拿掉擺放於位置1和19的板子就可以使板子之間最小的距離最大
### Solution
- Subtask 1：這題可以直接枚舉板子跟板子之間的最小距離，然後從大到小枚舉，一旦枚舉到都符合板子跟板子間的距離，就可以輸出答案，並且可以保證這是最大的。
- Subtask 2：這題為一個非常經典的二分搜題目，我們可以發現，對於每個數字只要小於最後的答案，都會小於板子跟板子間的最小距離。接下來就直接把枚舉換成二分搜，就可以找到答案了。
### Code
- Subtask 1
```cpp=
#include<iostream>
using namespace std;
int main()
{
    int n, k, t;
    cin >> n >> k >> t;
    int v[n + 2] = {0};
    v[0] = 0, v[n + 1] = t;
    for(int i = 1; i <= n; i++) cin >> v[i];
    for(int j = t; j >= 0; j--) {
        int last = 0;
        int notuse = 0;
        for(int i = 1; i <= n + 1; i++) {
            if(v[i] - last < j) notuse++;
            else last = v[i];
        }   
        if(notuse <= k) {
            cout << j << '\n';
            return 0;
        }
    }
    return 0;
}

```
- Subtask 2
```cpp=
#include<iostream>
using namespace std;
int main()
{
    int n, k, t;
    cin >> n >> k >> t;
    int v[n + 2] = {0};
    v[0] = 0, v[n + 1] = t;
    for(int i = 1; i <= n; i++) cin >> v[i];
    int l = 0, r = t;
    while(r > l) {
        int mid = (l + r + 1) / 2;
        int last = 0;
        int notuse = 0;
        for(int i = 1; i <= n + 1; i++) {
            if(v[i] - last < mid) notuse++;
            else last = v[i];
        }
        if(notuse <= k) l = mid;
        else r = mid - 1;
    }
    cout << l << '\n';
    return 0;
}

```

- 滿分 by 橘子
```cpp=
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
const ll big = 1e18;
int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    ll n,k,t;
    cin >> n >> k >> t;
    vector<ll> a(n);
    for(ll &i : a) cin >> i;
    ll l = 0,r = t/(n+1-k);
    while(l<r){
        ll x = l+r+1>>1;
        ll cnt = 0,last = 0;
        for(ll i : a){
            if (i-last>=x){
                last = i;
            }else{
                cnt++;
            }
        }
        cnt += t-last<x;
        if (cnt<=k){
            l = x;
        }else{
            r = x-1;
        }
    }
    cout << l << "\n";
}
```

```java=
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt(), k = scanner.nextInt(), t = scanner.nextInt();
        int[] a = new int[n];
        for (int i = 0; i < n; i++) {
            a[i] = scanner.nextInt();
        }
        int l = 0,r = t/(n+1-k);
        while (l<r){
            int x = l+r+1>>1;
            int cnt = 0,last = 0;
            for(int i : a){
                if (i-last>=x){
                    last = i;
                }else{
                    cnt++;
                }
            }
            if (t-last<x)cnt++;
            if (cnt<=k){
                l = x;
            }else{
                r = x-1;
            }
        }
        System.out.println(l);
        scanner.close();
    }
}
```

```python=
n,k,t = map(int,input().split())
a = list(map(int,input().split()))
l = 1
r = t//(n+1-k)
while l<r:
    x = l+r+1>>1
    last = 0
    cnt = 0
    for i in a:
        if i-last>=x:
            last = i
        else:
            cnt+=1
    if t-last<x:
        cnt+=1
    if cnt<=k:
        l = x
    else:
        r = x-1
print(l)
```

```python!
print((lambda n,k,t,a,o:o.__setitem__(1,t//(n+1-k)) or a.append(t) or any(o.__setitem__(2,0) or (o.__setitem__(0,x) if sum(i-o[2]<x or o.__setitem__(2,i) or 0 for i in a)<=k else o.__setitem__(1,x-1)) for x in iter(lambda:o[0]<o[1] and sum(o[:2])+1>>1,False)) or o[0])(*map(int,input().split()),list(map(int,input().split())),[1,1,0]))
```
## 電線 (Wire)
> 出題者：Mingyee
> 難度：P4
> 考點：樹DP
### Statement
Yee 星人的星球上有 $n$ 個城市

Yee 星人發現了一種室溫超導體，可以讓電無耗損傳播

於是他們規劃了一個供電網路，為了減少成本，他們以 $n-1$ 條電纜正好連接著 $n$ 個城市，使得不管發電機在哪個城市，每個城市都能獲得電的供應

不過實際應用後他們發現這個室溫超導體與理想狀況有些區別，電力實際只能傳播到**周遭以一條電纜連結**的城市

例如供電網路如下 
```
1-2-3-4
```
若發電機在 $2$，電力只能傳播到 $1$ 和 $3$，而不能傳播到 $4$

於是無奈的 Yee 星人只好建造多個發電機解決這個問題

已知在第 $i$ 個城市建造發電機的成本為 $p_i$

不過 Yee 星人的城市十分龐大
所以他們聘請了與電神奮戰多年的你，幫他們撰寫一個城市來計算欲使所有城市獲得供電，所需要建造發電廠的**最低成本**

### Input

第一行輸入一個正整數 $n$，表示城市數量 $(1\le n \le 2 \times 10^5)$

接下來有 $n-1$ 行，每行輸入兩個**相異**正整數 $a$ $b$，表示城市 $a$ 與城市 $b$ 間有一條電纜連接 $(1 \le a, b \le n)$

第 $n+1$ 行輸入 $n$ 個整數，代表序列 $\lt p \gt$，其中 $p_i$ 代表在第 $i$ 個城市建造發電機的成本 $( 0\le p_i \le 10^9, 1 \le i \le n)$

所有測資保證供電網路中從任意城市出發，任意城市為終點，洽能找到**唯一**的一條電傳播路徑，且輸入無重複的 $(a, b)$

### Output
輸出一個正整數，代表使所有城市獲得電供應所需的最低成本

### Input Example
- Input 1
```
4
1 2
2 3
3 4
1 2 4 1
```
- Output 1
```
2
```

- Input 2
```
5
1 2
1 3
3 4
4 5
1 2 2 4 3
```
- Output 2
```
4
```
### Subtask
- Subtask 1 (30%) $n \le 20$
- Subtask 2 (20%) $\forall(a,b)\ a = b+1$ 且 $p_i = 1, (1 \le i \le n)$
- Subtask 3 (50%) 無其他限制

### Note


### Solution


### Code

### Subtask 1: 枚舉

### Subtask 2 :
```python=
n = int(input())
print( n//3 + (n%3 >0) , end = "")
```

### Subtask 3 樹DP
dp[x][0] 選x所需的最小值(以x為根，ignore所有父節點以上節點)
dp[x][1] 不選x且 不選x的父節點所需最小值
dp[x][2] 不選x且 選x的父節點所需最小值

答案= min(dp[rt][0], dp[rt][1]) (因為rt沒父節點)
```cpp=
#include <bits/stdc++.h>
#define int int64_t
#define endl "\n"
#define pb push_back
 
using namespace std;
constexpr int MAX_N = 2e5+5;
vector<int> G[MAX_N];
bool vis[MAX_N];
int dp[MAX_N][3];
int ans;
int dfs(int v, int p){
    bool mk = 0;
    int minn  = LLONG_MAX;
    for(auto a : G[v]){
        if(p == a) continue;
        dp[v][0] += dfs(a, v);
        dp[v][2] += min(dp[a][1], dp[a][0]);
        dp[v][1] += min(dp[a][1], dp[a][0]);

        if(dp[a][0] <= dp[a][1]) mk = 1;
        else minn = min(minn, dp[a][0] - dp[a][1]);
    }
    if(!mk) dp[v][1] += minn;
    //cout << "vis" << v << ' ' << dp[v][0] << ' ' << dp[v][1] <<  ' ' << dp[v][2] <<  endl;
    return min({dp[v][0], dp[v][1], dp[v][2]});
}
 

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    int n, a, b;
    cin >> n;
    for(int x=0; x<n-1; x++){
        cin >> a >> b;
        G[a].pb(b);
        G[b].pb(a);
    }
    for(int x=1; x<=n; x++){
        cin >> dp[x][0];
    }
    dfs(1, 0);
    cout << min(dp[1][0], dp[1][1]);
    return 0;
}
```

### 稍微不同的DP定義 by 橘子

```cpp=
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
const ll big = 1e18;
struct obj{
    ll a,b,c; // choose has no
};
int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    ll n;
    cin >> n;
    vector<vector<ll>> con(n);
    for(ll i = 1;i<n;i++){
        ll u,v;
        cin >> u >> v;
        con[u-1].push_back(v-1);
        con[v-1].push_back(u-1);
    }
    vector<ll> a(n);
    for(ll &i : a) cin >> i;
    function<obj(ll,ll)> dfs;
    dfs = [&](ll i, ll p){
        ll s1 = 0, s2 = 0, s3 = big;
        for(ll j : con[i]) if(j!=p){
            obj o = dfs(j,i);
            s1 += o.c;
            s2 += o.b;
            s3 = min(s3,o.a-o.b);
        }
        obj ret = {s1+a[i],s2+s3,s2};
        ret.b = min(ret.b,ret.a);
        ret.c = min(ret.c,ret.b);
        return ret;
    };
    obj o = dfs(0,-1);
    cout << o.b << "\n";
}
```

```java=
import java.util.*;

public class Main {
    static int n;
    static ArrayList<ArrayList<Integer>> con;
    static int[] a;
    public static int[] dfs(int i, int p){
        int s1 = 0,s2 = 0,s3 = 1000000000;
        for(int j : con.get(i))if(j != p){
            int[] o = dfs(j,i);
            s1 += o[2];
            s2 += o[1];
            s3 = Math.min(s3,o[0]-o[1]);
        }
        int[] ret = new int[]{s1+a[i],s2+s3,s2};
        ret[1] = Math.min(ret[1],ret[0]);
        ret[2] = Math.min(ret[2],ret[1]);
        return ret;
    }
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        n = scanner.nextInt();
        con = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            con.add(new ArrayList<>());
        }
        for (int i = 0; i < n-1; i++) {
            int u = scanner.nextInt()-1, v = scanner.nextInt()-1;
            con.get(u).add(v);
            con.get(v).add(u);
        }
        a = new int[n];
        for (int i = 0; i < n; i++) {
            a[i] = scanner.nextInt();
        }
        System.out.println(dfs(0,-1)[1]);
        scanner.close();
    }
}
```

```python=
import sys
sys.setrecursionlimit(1000000)
n = int(input())
con = [[] for _ in range(n)]
for _ in range(n-1):
    u,v = map(int,input().split())
    con[u-1].append(v-1)
    con[v-1].append(u-1)
a = list(map(int,input().split()))
def dfs(i,p):
    s1 = 0
    s2 = 0
    s3 = 10**10
    for j in con[i]:
        if j != p:
            o = dfs(j,i)
            s1 += o[2]
            s2 += o[1]
            s3 = min(s3,o[0]-o[1])
    ret = [s1+a[i],s2+s3,s2]
    ret[1] = min(ret[1],ret[0])
    ret[2] = min(ret[2],ret[1])
    return ret
print(dfs(0,-1)[1])
```

```python!
print((lambda n,f,fs:(lambda ls,con,a:any(con[u-1].append(v-1) or con[v-1].append(u-1) for u,v in ls) or (lambda dfs:dfs(dfs,0,-1)[1])(lambda dfs,i,p:(lambda l:(l[0]+a[i],min(l[0]+a[i],l[1]+l[2]),min(l[0]+a[i],l[1])))([fs[i](o) for i,o in enumerate(zip(*(f(dfs(dfs,j,i)) if j != p else (0,0,10**10) for j in con[i])))])))(list(map(int,input().split()) for _ in range(n-1)),[[] for _ in range(n)],list(map(int,input().split()))))(int(input()),(lambda o:(o[2],o[1],o[0]-o[1])),(sum,sum,min)))
```