1. 程式人生 > >[bzoj3573] [HNOI2014]米特運輸

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

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

Solution

閱讀題。。

讀懂題意就差不多做完了。。

大意就是給你一棵樹,一開始每個點有一個權值,然後要你修改儘可能少的點權,使得每個點的點權等於他兒子的點權之和,且兒子的點權都相等。其中\(1\)為根節點。

可以發現確定了一個點的權值之後,整棵樹的權值都確定了,所以不妨設根節點的權值為\(x\),則對於點\(u\),權值就是:
\[ x\cdot \prod_{v\in chain(1\to u)}\frac{1}{deg[v]} \]
反過來,若不改變\(u\)的權值,就可以確定根節點的權值,設當前的權值為\(x\),則:
\[ val_{root}=x\cdot \prod deg[v] \]
由於後面那個玩意會爆\(long\,\,long\),所以(當然寫高精度啊)兩邊取\(\ln\)
\[ \ln val_{root}=\ln x + \sum \ln deg[v] \]
然後前面相等的時候屬於同一種方案,\(sort\)一下就行了。

#include<bits/stdc++.h>
using namespace std;

#define ONLINE_JUDGE

#ifdef ONLINE_JUDGE
#define getchar() ((p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin)),p1==p2)?EOF:*p1++)
#endif

namespace fast_IO {
    char buf[1<<21],*p1=buf,*p2=buf;

    template <typename T> inline void read(T &x) {
        x=0;T f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
    template <typename T,typename... Args> inline void read(T& x,Args& ...args) {
        read(x),read(args...);
    }

    char buf2[1<<21],a[80];int p,p3=-1;

    inline void flush() {fwrite(buf2,1,p3+1,stdout),p3=-1;}
    template <typename T> inline void write(T x) {
        if(p3>(1<<20)) flush();
        if(x<0) buf2[++p3]='-',x=-x;
        do {a[++p]=x%10+48;} while(x/=10);
        do {buf2[++p3]=a[p];} while(--p);
        buf2[++p3]='\n';
    }
    template <typename T,typename... Args> inline void write(T x,Args ...args) {
        write(x),write(args...);
    }
}

using fast_IO :: read;
using fast_IO :: write;
using fast_IO :: flush;

#define lf double 
#define ln log

const lf eps = 1e-8;
const int maxn = 5e5+10;

int val[maxn],n,deg[maxn],head[maxn],tot;;
lf f[maxn];
struct edge{int to,nxt;}e[maxn<<1];

void add(int u,int v) {e[++tot]=(edge){v,head[u]},head[u]=tot;}
void ins(int u,int v) {add(u,v),add(v,u);}

void dfs(int x,int fa) {
    for(int i=head[x];i;i=e[i].nxt)
        if(e[i].to!=fa) f[e[i].to]=f[x]+ln(deg[x]-(x!=1)),dfs(e[i].to,x);
}

int main() {
    read(n);for(int i=1;i<=n;i++) read(val[i]);
    for(int i=1,x,y;i<n;i++) read(x,y),ins(x,y),deg[x]++,deg[y]++;
    f[1]=1;dfs(1,0);
    for(int i=1;i<=n;i++) f[i]=f[i]+ln(val[i]);
    sort(f+1,f+n+1);int p=1,ans=1e9;
    for(int i=2;i<=n;i++) {
        if(f[i]-f[i-1]>eps) p=i;
        ans=min(ans,n-(i-p+1));
    }write(ans);
    flush();
    return 0;
}