uva 12223 - Moving to Nuremberg

来源:互联网 发布:淘宝卖家说加微信返现 编辑:程序博客网 时间:2024/06/05 21:02

Moving to Nuremberg

题目描述:

给出n,表示有n个位置,n个位置有n-1条边,形成一个无根的树,每条边上都有权值。现在每个位置都有一个景点,一个人想在一年之内去ki次景点,所以接下来给出m,表示说在m个位置上有这个人想去的地方,给出位置以及想去的次数(注意,每去一个景点都要返回自己的住处),然后问说,这个人该住在哪里走的路程才最短。

题解:

常用的一种简单的树上枚举根的转移方法.第一次以1为根树形dp,搞出以u为根的到1的总距离.然后开始在树上转移.如果有fa的结果,怎么算出u的结果?本题并不需要改dp值,并且改dp值需要改的东西太多.直接算就行了,因为u的儿子的总有效个数知道了,那么就是减少了这么多,增加了剩下那么多的2*fa_u_len,就得到结果了.因此dp也不要放对答案的贡献了,直接放个数就好…

重点:

树形dp+在树上枚举根节点进行快速转移

代码:

#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <cmath>#include <ctype.h>#include <limits.h>#include <cstdlib>#include <algorithm>#include <vector>#include <queue>#include <map>#include <stack>#include <set>#include <bitset>#define CLR(a) memset(a, 0, sizeof(a))#define REP(i, a, b) for(ll i = a;i < b;i++)#define REP_D(i, a, b) for(ll i = a;i <= b;i++)typedef long long ll;using namespace std;const ll maxn = 50000 + 100;ll n, num[maxn], c[maxn], dp[maxn];//其实dp不用也行,主要是num和之后计算出1为根,之后再转移根struct info{    ll to, len, next;};info edge[maxn*2 +1];ll sum;ll tot, head[maxn];ll ans;ll ans_i[maxn], now;void add_edge(ll a, ll b, ll len){    edge[tot].to = b;    edge[tot].len = len;    edge[tot].next = head[a];    head[a] = tot;    tot++;    edge[tot].to = a;    edge[tot].len = len;    edge[tot].next = head[b];    head[b] = tot;    tot++;}void dfs_num(ll u, ll fa){    num[u] = c[u];    for(ll i = head[u]; i!=-1; i = edge[i].next)    {        ll v = edge[i].to, len = edge[i].len;        if(v!=fa)        {            dfs_num(v, u);            num[u] += num[v];        }    }}void dfs_first(ll u, ll fa, ll road){    dp[1] += (c[u]*road*2);    for(ll i = head[u]; i!=-1; i = edge[i].next)    {        ll v = edge[i].to, len = edge[i].len;        if(v!=fa)        {            dfs_first(v, u, road+len);        }    }}void dfs(ll u, ll fa, ll fa_ans, ll fa_len){    if(fa==0)    {        for(ll i = head[u]; i!=-1; i = edge[i].next)        {            ll v = edge[i].to, len = edge[i].len;            if(v!=fa)            {                dfs(v, u, dp[u], len);            }        }    }    else    {        dp[u] = fa_ans;        dp[u] -= 2*fa_len*num[u];        dp[u] += 2*fa_len*(sum-num[u]);        for(ll i = head[u]; i!=-1; i = edge[i].next)        {            ll v = edge[i].to, len = edge[i].len;            if(v!=fa)            {                dfs(v, u, dp[u], len);            }        }    }}void solve(){    dfs_num(1, 0);    dp[1] = 0;    dfs_first(1, 0, 0);    dfs(1, 0, 0, 0);    ans = 10000000000000000ll;    now = 0;    REP_D(i, 1, n)    {        if(dp[i] < ans)        {            ans = dp[i];            now = 0;            ans_i[now] = i;            now++;        }        else if(dp[i]==ans)        {            ans_i[now] = i;            now++;        }    }    sort(ans_i, ans_i + now);    printf("%lld\n", ans);    REP(i, 0, now)    {        printf("%lld%c", ans_i[i], (i==now-1 ? '\n' : ' '));    }}int main(){    //freopen("8Hin.txt", "r", stdin);    //freopen("8Hout.txt", "w", stdout);    int ncase;    scanf("%d", &ncase);    while(ncase--)    {        scanf("%lld", &n);        memset(head, -1, sizeof(head));        tot = 0;        //CLR(num);        sum = 0;        CLR(c);        REP_D(i, 1, n - 1)        {            ll a, b, len;            scanf("%lld%lld%lld", &a, &b, &len);            add_edge(a, b, len);        }        ll t;        scanf("%lld", &t);        while(t--)        {            ll a, b;            scanf("%lld%lld", &a, &b);            c[a] += b;            sum += b;        }        solve();    }    return 0;}
0 0
原创粉丝点击