1. 程式人生 > >[HNOI 2014]米特運輸

[HNOI 2014]米特運輸

原本 style aws namespace output 方向 input 父親 next

Description

米特是D星球上一種非常神秘的物質,蘊含著巨大的能量。在以米特為主要能源的D星上,這種米特能源的運輸和儲 存一直是一個大問題。D星上有N個城市,我們將其順序編號為1到N,1號城市為首都。這N個城市由N-1條單向高速 通道連接起來,構成一棵以1號城市(首部)為根的樹,高速通道的方向由樹中的兒子指向父親。樹按深度分層: 根結點深度為0,屬於第1層;根結點的子節點深度為1,屬於第2層;依此類推,深度為i的結點屬於第i+l層。建好 高速通道之後,D星人開始考慮如何具體地儲存和傳輸米特資源。由於發展程度不同,每個城市儲存米特的能力不 盡相同,其中第i個城市建有一個容量為A[i]的米特儲存器。這個米特儲存器除了具有儲存的功能,還具有自動收
集米特的能力。如果到了晚上六點,有某個儲存器處於未滿的狀態,它就會自動收集大氣中蘊含的米特能源,在早 上六點之前就能收集滿;但是,只有在儲存器完全空的狀態下啟動自動收集程序才是安全的,未滿而又非空時啟動 可能有安全隱患。早上六點到七點間,根節點城市(1號城市)會將其儲存器裏的米特消耗殆盡。根節點不會自動 搜集米特,它只接受子節點傳輸來的米特。早上七點,城市之間啟動米特傳輸過程,傳輸過程逐層遞進:先是第2 層節點城市向第1層(根節點城市,即1號城市)傳輸,直到第1層的儲存器滿或第2層的儲存器全為空;然後是第3 層向第2層傳輸,直到對於第2層的每個節點,其儲存器滿或其予節點(位於第3層)的儲存器全為空;依此類推,
直到最後一層傳輸完成。傳輸過程一定會在晚上六點前完成。 由於技術原因,運輸方案需要滿足以下條件: (1)不能讓某個儲存器到了晚上六點傳輸結束時還處於非空但又未滿的狀態,這個時候儲存器仍然會啟動自動收集 米特的程序,而給已經儲存有米特的儲存器啟動收集程序可能導致危險,也就是說要讓儲存器到了晚上六點時要麽 空要麽滿; (2)關於首都——即1號城市的特殊情況, 每天早上六點到七點間1號城市中的米特儲存器裏的米特會自動被消耗 殆盡,即運輸方案不需要考慮首都的米特怎麽運走; (3)除了1號城市,每個節點必須在其子節點城市向它運輸米特之前將這座城市的米特儲存器中原本存有的米特全部
運出去給父節點,不允許儲存器中殘存的米特與外來的米特發生混合; (4)運向某一個城市的若幹個來源的米特數量必須完全相同,不然,這些來源不同的米特按不同比例混合之後可能 發生危險。 現在D星人已經建立好高速通道,每個城市也有了一定儲存容量的米特儲存器。為了滿足上面的限制條件,可能需 要重建一些城市中的米特儲存器。你可以,也只能,將某一座城市(包括首都)中屎來存在的米特儲存器摧毀,再 新建一座任意容量的新的米特儲存器,其容量可以是小數(在輸入數據中,儲存器原始容量是正整數,但重建後可 以是小數),不能是負數或零,使得需要被重建的米特儲存器的數目盡量少。

Input

第一行是一個正整數N,表示城市的數目。接下來N行,每行一個正整數,其中的第i行表示第i個城市原來存在的米 特儲存器的容量。再接下來是N-I行,每行兩個正整數a,b表示城市b到城市a有一條高速通道(a≠b)。 N<500000,A[j]<10^8

Output

輸出文件僅包含一行,一個整數,表示最少的被重建(即修改儲存器容量)的米特儲存器的數目。

Sample Input

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

Sample Output

3

HINT

【樣例解釋】
一個最優解是將A[1]改成8,A[3]改成4,A[5]改成2。這樣,2和3運給1的量相等,4和5運給2的量相等,且每天晚上六點的時候,1,2滿,3,4,5空,滿足所有限制條件。

題目大意

給一棵樹,每個點有一個權值,要求修改一些點的權值,使得:

①同一個父親的兒子權值必須相同

②父親的取值必須是所有兒子權值之和

題解

有這樣一個結論,當這棵樹的任何一個節點的權值確定之後,其余所有節點的權值便都可算出來。

例如下圖:

技術分享圖片

若我們確定了 $5$ 號節點的權值為 $x$ ,那麽 $7$ 號節點的權值 $y$ 可以算出 $y = \frac{3}{2} \cdot x$ 。

現在我們將每一條邊定向,方向為從父親指向兒子,對於每個節點,統計每個節點的出度,做一遍樹上前綴積 $prod_u$ 。例如上圖中 $prod_5 = 6$ , $prod_7 = 4$ ,特別地 $prod_1 = 1$ 。

我們假設 $u$ 節點的權值是不變的,那麽必然有修改後的根節點的權為 $w = a_u \cdot prod_u$。

記 $f_u = prod_u*a_u$ ,我們將樹上 $f_u$ 相同的點放在一組,現在問題就變成了求點數最多的一組的點的個數。

由於乘積過大,直接 $hash$ 。

 1 //It is made by Awson on 2018.1.3
 2 #include <set>
 3 #include <map>
 4 #include <cmath>
 5 #include <ctime>
 6 #include <queue>
 7 #include <stack>
 8 #include <cstdio>
 9 #include <string>
10 #include <vector>
11 #include <cstdlib>
12 #include <cstring>
13 #include <iostream>
14 #include <algorithm>
15 #define LL long long
16 #define LD long double
17 #define Max(a, b) ((a) > (b) ? (a) : (b))
18 #define Min(a, b) ((a) < (b) ? (a) : (b))
19 using namespace std;
20 const int N = 500000;
21 const int MOD1 = 1e6+9;
22 const int MOD2 = 1e6+7;
23 const int MOD3 = 1e6-3;
24 
25 int a[N+5], u, v, n;
26 struct tt {
27     int to, next;
28 }edge[(N<<1)+5];
29 int path[N+5], top, degree[N+5];
30 int hash1[MOD1+5], hash2[MOD2+5], hash3[MOD3+5];
31 int ans1, ans2, ans3;
32 
33 void add(int u, int v) {
34     edge[++top].to = v;
35     edge[top].next = path[u];
36     path[u] = top;
37 }
38 void dfs(int u, int fa, int num1, int num2, int num3) {
39     int tmp, d = --degree[u];
40     tmp = ++hash1[(LL)num1*a[u]%MOD1], ans1 = Max(ans1, tmp);
41     tmp = ++hash2[(LL)num2*a[u]%MOD2], ans2 = Max(ans2, tmp);
42     tmp = ++hash3[(LL)num3*a[u]%MOD3], ans3 = Max(ans3, tmp);
43     for (int i = path[u]; i; i = edge[i].next)
44     if (edge[i].to != fa) dfs(edge[i].to, u, (LL)num1*d%MOD1, (LL)num2*d%MOD2, (LL)num3*d%MOD3);
45 }
46 void work() {
47     scanf("%d", &n);
48     for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
49     for (int i = 1; i < n; i++) {
50     scanf("%d%d", &u, &v);
51     add(u, v), add(v, u); ++degree[u], ++degree[v];
52     }
53     ++degree[1];
54     dfs(1, 0, 1, 1, 1);
55     printf("%d\n", n-Min(Min(ans1, ans2), ans3));
56 }
57 int main() {
58     work();
59     return 0;
60 }

[HNOI 2014]米特運輸