bzoj3573: [Hnoi2014]米特運輸

題目鏈接

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)。

Output

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

Sample Input

5
5
4
3
2
1
12
13
24
25

Sample Output

3

HINT

【樣例解釋】
一個最優解是將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

題解

裸題意就是修改儘量少的點,使得
1.每個非葉子節點的權值等於子節點權值之和。
2.一個節點的所有子節點的權值相同。

我們注意到只有一個點的權值確定了,那麼所有點的權值都確定了。我們可以枚舉不動點,計算有多少點的權值不會改變,取最大值。但這樣是n2 的時間複雜度。仔細想想會發現如果A點權值不變時B點權值也不變,那麼當A或B權值不變時根節點的權值是相同的。也就是說我們只有計算出每個點不變時根節點的權值,取一個衆數就行了。實現時可以由根節點向下dfs一次,算出每個點的權值需要乘多少。但數字很大,可以hash或取對數。


#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;

#define N 500010
int du[N],first[N],c[N],a[N],cnt,ans,p,x,y,q,n,tot;
double dis[N];
struct edge{int x,next;}e[N];

char BUF[200001],*buf,*end;
#define getch() (buf==end?fread(BUF,1,200000,stdin),buf=BUF,end=buf+200000,*(buf++):*(buf++))
inline void read(int &x){
    static char c;
    for(c=getch();c<'0'||c>'9';c=getch());
    for(x=0;'0'<=c&&c<='9';c=getch())x=x*10+c-'0';
}

void add(int x,int y){
    e[++tot].x=y;
    e[tot].next=first[x];
    first[x]=tot;
}
int main(){
    read(n);
    for(int i=1;i<=n;i++) read(a[i]);
    for(int i=1;i<n;i++){
        read(x); read(y);
        add(x,y); du[x]++;
    } 
    c[p=q=1]=1;
    for(;p<=q;p++){
        double tmp=log(du[c[p]]);
        for(int i=first[c[p]];i;i=e[i].next)
        dis[e[i].x]=dis[c[p]]+tmp,c[++q]=e[i].x;
    }
    for(int i=1;i<=n;i++) dis[i]+=log(a[i]);
    sort(dis+1,dis+1+n);
    for(int i=1;i<=n;i++)
    if(dis[i]-dis[i-1]<1e-4) cnt++;
    else ans=max(cnt,ans),cnt=1;
    ans=max(cnt,ans);
    printf("%d\n",n-ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章