BZOJ 3573 米特运输

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
I
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

 

Source

别人都说读懂了题目是到水题,但是我做并没有想象中那么水啊,我还是翻了题解的。。。QAQ,一定是我太弱了。。。

其实做法还是很好理解的。任意两个点的倍率关系是确定的(若a是b的孩子,b又有k个孩子,则A[b]=k*A[a],利用这个关系可以推出任意两个点的关系。做的时候脑袋蠢了,没有想到这一点)。设dis[i]为修改后A[1]=dis[i]*A[i],那么依题意当a不修改时b不修改当且仅当A[a]*dis[a]=A[b]*dis[b],因此我们就可以反过来想。求最少修改的不就是求最多的不修改的吗???我们知道所有的A[i]*dis[i],看哪一个值最多就可以了。

但是dis数组值有可能会很大,我们有两种应对的策略——(取对数再sort(取对数是个很重要的处理方法),哈希)。

 

 1 #include<algorithm>
 2 #include<cmath>
 3 #include<vector>
 4 #include<iostream>
 5 #include<cstdio>
 6 #include<cstdlib>
 7 using namespace std;
 8 
 9 typedef long double ld;
10 #define maxn (500010)
11 #define inf (1 << 30)
12 #define eps (1e-11)
13 int n,next[maxn<<1],toit[maxn<<1],fa[maxn];
14 int side[maxn],cnt,team[maxn],d[maxn];
15 ld A[maxn],dis[maxn],bac[maxn]; bool in[maxn];
16 
17 inline bool equal(ld a,ld b) { return fabs(a-b) <= eps; }
18 
19 inline void add(int a,int b) { next[++cnt] = side[a]; side[a] = cnt; toit[cnt] = b; }
20 
21 inline void ins(int a,int b) { add(a,b); add(b,a); }
22 
23 inline void bfs()
24 {
25     int h = 0,t = 0;
26     in[1] = true; team[++t] = 1;
27     while (h != t)
28     {
29         int now = team[++h];
30         for (int i = side[now];i;i = next[i])
31             if (!in[toit[i]])
32                 in[toit[i]] = true,team[++t] = toit[i],fa[toit[i]] = now,++d[now];
33     }
34     for (int i = 2;i <= n;++i)
35         dis[team[i]] = dis[fa[team[i]]] + log(d[fa[team[i]]]);
36 }
37 
38 inline void work()
39 {
40     int res = 1,cnt; ld last = -1;
41     for (int i = 1;i <= n;++i) bac[i] = dis[i] + A[i];
42     sort(bac+1,bac+n+1);
43     for (int i = 1;i <= n;++i)
44     {
45         if (equal(bac[i],last)) res = max(res,++cnt);
46         else last = bac[i],cnt = 1;
47     }
48     printf("%d",n-res);
49 }
50 
51 int main()
52 {
53     freopen("3573.in","r",stdin);
54     freopen("3573.out","w",stdout);
55     int a,b; scanf("%d",&n);
56     for (int i = 1;i <= n;++i) scanf("%d",&a),A[i] = log(a);
57     for (int i = 1;i < n;++i) scanf("%d %d",&a,&b),ins(a,b);
58     bfs(); work();
59     fclose(stdin); fclose(stdout);
60     return 0;
61 }
View Code

 

posted @ 2015-02-22 20:12  lmxyy  阅读(201)  评论(0编辑  收藏  举报