[USACO10MAR]伟大的奶牛聚集

[USACO10MAR]伟大的奶牛聚集

Bessie正在计划一年一度的奶牛大集会,来自全国各地的奶牛将来参加这一次集会。当然,她会选择最方便的地点来举办这次集会。

每个奶牛居住在 N(1<=N<=100,000) 个农场中的一个,这些农场由N-1条道路连接,并且从任意一个农场都能够到达另外一个农场。道路i连接农场A_i和B_i(1 <= A_i <=N; 1 <= B_i <= N),长度为L_i(1 <= L_i <= 1,000)。集会可以在N个农场中的任意一个举行。另外,每个牛棚中居住者C_i(0 <= C_i <= 1,000)只奶牛。

在选择集会的地点的时候,Bessie希望最大化方便的程度(也就是最小化不方便程度)。比如选择第X个农场作为集会地点,它的不方便程度是其它牛棚中每只奶牛去参加集会所走的路程之和,(比如,农场i到达农场X的距离是20,那么总路程就是C_i*20)。帮助Bessie找出最方便的地点来举行大集会。                                   ——by洛谷(感谢洛谷少有的良心翻译)

http://daniu.luogu.org/problem/show?pid=2986

《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《

建图,然后把它当做以任意点为根的树,然后很容易想用树DP。我们发现a与其父节点b;a为集合点的路径有两类:

  1. 直接到a;(我们把到a路径符合此类的点集记为A);
  2. 先到b;(我们把到a路径符合此类的点集记为B);

于是当我们知道f[b]时,f[a]即为在f[b]的基础上A中点不必走a->b,B中点要再走b->a,而A即是a的子树点集;

得方程:

f[a]=f[fa[a]]-tree[a]*dis(a->b)+(tree[root]-tree[a])*dis(a->b);

(想象所有点先聚集于b,再全走到a,其中a的子树上节点多走了,故减去)

代码如下:

#include<cstdio>
using namespace std;
int n;
int c[100001];
long long f1[100001],f[100001];
struct ss
{
    int next,to,dis;
}x[200000];
int first[100001],num;
long long all;
void build(int f,int t,int d)
{
    x[++num].next=first[f];
    x[num].to=t;
    x[num].dis=d;
    first[f]=num;
}
long long dfs(int ,int );
void dp(int ,int ,int );

int main()
{
    scanf("%d",&n);
    int i,j,k,l;
    for(i=1;i<=n;i++)
        scanf("%d",&c[i]),all+=c[i];
    for(i=1;i<=n-1;i++)
    {
        scanf("%d%d%d",&j,&k,&l);
        build(j,k,l);
        build(k,j,l);
    }
    f[0]=dfs(1,-1);
    dp(1,0,0);
    all=100000000000000000;
    for(i=1;i<=n;i++)
    if(f[i]<all)
        all=f[i];
    printf("%lld",all);
    return 0;
}

long long dfs(int fa,int last)
{
    int j;
    long long sum=0;
    j=first[fa];
    f1[fa]=c[fa];
    while(j)
    {
        if(x[j].to!=last)
        {
            sum+=dfs(x[j].to,fa)+x[j].dis*f1[x[j].to];
            f1[fa]+=f1[x[j].to];
        }
        j=x[j].next;
    }
    return sum;
}
void dp(int fa,int last,int di)
{
    int j;
    f[fa]=f[last]-f1[fa]*di+(all-f1[fa])*di;
    j=first[fa];
    while(j)
    {
        if(x[j].to!=last)
            dp(x[j].to,fa,x[j].dis);
        j=x[j].next;
    }
}

祝AC;

时间: 2024-08-04 18:24:08

[USACO10MAR]伟大的奶牛聚集的相关文章

题解 P2986 [USACO10MAR]伟大的奶牛聚集

题解 P2986 [USACO10MAR]伟大的奶牛聚集 题目链接 很好的一道树形dp的题目,我们观察每一个点i的答案,发现答案 f[i] 由两部分组成: A1.i所有子树中的犇集中到i点 A2.除了i的子树中的所有犇集中到i的父亲节点,再走到i点 f[i] = A1 + A2 我们发现i的答案和i的孩子有关,也和i的父亲有关.一般这样的问题用两次dfs就可以解决.(由于选谁是根节点都无所谓,以下以1号节点为根) 第一次dfs我们求出每一个点的 f[i], 意思是以i为根节点的子树中的牛集中到i

洛谷 P2986 [USACO10MAR]伟大的奶牛聚集(树形动规)

题目描述 Bessie is planning the annual Great Cow Gathering for cows all across the country and, of course, she would like to choose the most convenient location for the gathering to take place. Bessie正在计划一年一度的奶牛大集会,来自全国各地的奶牛将来参加这一次集会.当然,她会选择最方便的地点来举办这次集会

BZOJ 1827 洛谷 2986 [USACO10MAR]伟大的奶牛聚集Great Cow Gather

[题解] 很容易想到暴力做法,枚举每个点,然后对于每个点O(N)遍历整棵树计算答案.这样整个效率是O(N^2)的,显然不行. 我们考虑如果已知当前某个点的答案,如何快速计算它的儿子的答案. 显然选择它的儿子作为集合点,它的儿子的子树内的奶牛可以少走当前点到儿子节点的距离dis,不在它儿子的子树内的奶牛要多走dis. 那么我们维护每个节点的子树内的奶牛总数(即点权和),就可以快速进行计算了.效率O(N). 1 #include<cstdio> 2 #include<algorithm>

P2986 [USACO10MAR]伟大的奶牛聚集Great Cow Gat…

题目描述 Bessie is planning the annual Great Cow Gathering for cows all across the country and, of course, she would like to choose the most convenient location for the gathering to take place. Bessie正在计划一年一度的奶牛大集会,来自全国各地的奶牛将来参加这一次集会.当然,她会选择最方便的地点来举办这次集会

P2986 [USACO10MAR]伟大的奶牛聚集(思维,dp)

题目描述 Bessie is planning the annual Great Cow Gathering for cows all across the country and, of course, she would like to choose the most convenient location for the gathering to take place. Bessie正在计划一年一度的奶牛大集会,来自全国各地的奶牛将来参加这一次集会.当然,她会选择最方便的地点来举办这次集会

[USACO10MAR] 伟大的奶牛聚集 - 树形dp

每个点有重数,求到所有点距离最小的点 就是魔改的重心了 #include <bits/stdc++.h> using namespace std; #define int long long const int N = 1000005; vector <pair<int,int> > g[N]; int siz[N],f[N],vis[N],sum[N],c[N],n,m,t1,t2,t3,tot; void dfs1(int p) { vis[p]=1; siz[p]

P2986 [USACO10MAR]伟大的奶牛聚集

题意: 给一棵 n 个点的边 + 点权树,求带权重? 思路: 其实这题和之前那个 Sta 有点像,我们同样只需要预处理出一个 f[u] 代表以 u 为集合点的方便程度,那么我们就可以O(1)的转移了 假设 v 是 u 的儿子,f[v] = f[u] - (siz[v] * len) + (n - siz[v] ) * len = f[u] + (n - 2 * siz[v] )  * len 这题有一个坑,就是你的INF得开的特别大,不然你就没有 100 了 #include <iostream

洛谷 P2986 [USACO10MAR]Great Cow Gat…(树形dp+容斥原理)

P2986 [USACO10MAR]伟大的奶牛聚集Great Cow Gat… 题目描述 Bessie is planning the annual Great Cow Gathering for cows all across the country and, of course, she would like to choose the most convenient location for the gathering to take place. Each cow lives in on

饥饿的奶牛(洛谷 1868)

题目描述 有一条奶牛冲出了围栏,来到了一处圣地(对于奶牛来说),上面用牛语写着一段文字. 现用汉语翻译为: 有N个区间,每个区间x,y表示提供的x~y共y-x+1堆优质牧草.你可以选择任意区间但不能有重复的部分. 对于奶牛来说,自然是吃的越多越好,然而奶牛智商有限,现在请你帮助他. 输入输出格式 输入格式: 第一行,N,如题 接下来N行,每行一个数x,y,如题 输出格式: 一个数,最多的区间数 输入输出样例 输入样例#1: 3 1 3 7 8 3 4 输出样例#1: 5 说明 1<=n<=15