[HNOI2014]米特運輸
題目描述
米特是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星人已經建立好高速通道,每個城市也有了一定儲存容量的米特儲存器。為了滿足上面的限制條件,可能需要重建一些城市中的米特儲存器。你可以,也只能,將某一座城市(包括首都)中屎來存在的米特儲存器摧毀,再新建一座任意容量的新的米特儲存器,其容量可以是小數(在輸入數據中,儲存器原始容量是正整數,但重建後可以是小數),不能是負數或零,使得需要被重建的米特儲存器的數目盡量少。
輸入輸出格式
輸入格式:
第一行是一個正整數N,表示城市的數目。 接下來N行,每行一個正整數,其中的第i行表示第i個城市原來存在的米特儲存器的容量。 再接下來是N-I行,每行兩個正整數a,b表示城市b到城市a有一條高速通道(a≠b)。
輸出格式:
輸出文件僅包含一行,一個整數,表示最少的被重建(即修改儲存器容量)的米特儲存器的數目。
輸入輸出樣例
輸入樣例#1:5 5 4 3 2 I 12 13 24 25輸出樣例#1:
3
說明
【樣例解釋】
一個最優解是將A[1]改成8,A[3]改成4,A[5]改成2。這樣,2和3運給1的量相等,4和5運
給2的量相等,且每天晚上六點的時候,1,2滿,3,4,5空,滿足所有限制條件。
對於100%的數據滿足N<500000,A[j]<10^8
一道被題面包裝的非常嚇人的水題..
看了很久題目,大致是這個意思:
要你求最少需要改幾個點的權值,使得整顆樹的每個節點的權值為他子節點的權值之和,且他的子節點的權值都一樣.
先是可以發現當任意一個節點的權值確定之後,整棵樹的權值都可以確定.
然後就可以求出每一個點不改權值時根節點的權值是多少,記為dis[i].
那麽若i和j的dis值相同,則說明i和j可以同時不改權值.
那麽要求的就是n-最多有多少個點dis相同.
註意直接乘會炸LL,根據數學必修1中的那套理論,ln(a*b)=ln(a)+ln(b).
那麽取個對數就可以了.
1 #include<bits/stdc++.h> 2 #define maxn 500010 3 #define LL long long 4 #define eps 1e-9 5 using namespace std; 6 struct data{ 7 int nex,to; 8 }e[maxn*2]; 9 int head[maxn],edge=0; 10 double dis[maxn],w[maxn]; 11 inline void add(int from,int to){ 12 e[++edge].nex=head[from]; 13 e[edge].to=to; 14 head[from]=edge; 15 } 16 void dfs(int x,int fa,double ds){ 17 int sz=0; 18 dis[x]=ds+log(1.0*w[x]); 19 for(int i=head[x];i;i=e[i].nex) 20 if(e[i].to!=fa) sz++; 21 for(int i=head[x];i;i=e[i].nex){ 22 int v=e[i].to; 23 if(v==fa) continue; 24 dfs(v,x,ds+log(sz*1.0)); 25 } 26 } 27 int main(){ 28 int n,x,y; 29 scanf("%d",&n); 30 for(int i=1;i<=n;i++) 31 scanf("%lf",&w[i]); 32 for(int i=1;i<n;i++) 33 scanf("%d%d",&x,&y),add(x,y),add(y,x); 34 dfs(1,0,1.0); 35 sort(dis+1,dis+n+1); 36 int zd=0; 37 for(int i=1;i<=n;i++){ 38 int cnt=1; 39 while(i<=n && dis[i+1]+eps>=dis[i] && dis[i+1]-eps<=dis[i]) cnt++,i++; 40 zd=max(zd,cnt); 41 } 42 printf("%d",n-zd); 43 return 0; 44 }
[HNOI2014]米特運輸