[SCOI 2015集训]B

题目

思路

代码

好像ubuntu里写的代码,在win下面就wa了而且还会出现乱码注释。。。
注意INF定为1e18!输出在win下是I64d,不然只能拿到50分!

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

#define MAXN 1000010
#define INF 1e18

using namespace std;

typedef long long int LL;

struct edge
{
    int u,v,next;
}edges[MAXN*2];

int head[MAXN],nCount=0;

void AddEdge(int U,int V)
{
    edges[++nCount].u=U;
    edges[nCount].v=V;
    edges[nCount].next=head[U];
    head[U]=nCount;
}

//size[u]=瀛愭爲u澶у皬锛宯um[u]=缁撶偣u涓婄殑娲鹃仯娆℃暟锛宻um[u]=缁撶偣u涓婁竴鍏辨淳閬g殑澹叺涓暟
LL size[MAXN],num[MAXN],sum[MAXN],f[MAXN],g[MAXN]; //f[u]=浠涓烘牴鐨勫瓙鏍戜腑锛岃嫢u娲?涓汉锛寀鐨勫効瀛愭淳2浜猴紝瀛欏瓙娲?浜?..瀛愭爲u涓淳閬e+鍏垫€诲拰銆俫[u]=浠涓烘牴鐨勫瓙鏍戜腑娲鹃仯鐨勫+鍏垫€诲拰
int n,m;
LL ans[MAXN]; //ans[i]=灏嗙偣i浣滀负鏍硅妭鐐圭殑娲鹃仯澹叺鎬绘暟

void DFS1(int u,int fa)
{
    size[u]=1,f[u]=0,g[u]=0;
    for(int p=head[u];p!=-1;p=edges[p].next)
    {
        int v=edges[p].v;
        if(v==fa) continue;
        DFS1(v,u);
        size[u]+=size[v];
        f[u]+=f[v]+size[v];
        g[u]+=g[v];
    }
    g[u]+=f[u]*num[u]+sum[u]*size[u];
}

void DFS2(int u,int fa)
{
    ans[u]=g[u];
    for(int p=head[u];p!=-1;p=edges[p].next)
    {
        int v=edges[p].v;
        if(v==fa) continue;
        //鏀瑰彉鏈夊悜鏍戠粨鏋勶紝灏唙浣滀负u鐖朵翰锛屽厛鏇存柊u閲屽叧浜巚鐨勬墍鏈夊€?
        g[u]-=f[u]*num[u]+sum[u]*size[u]; //閲嶇疆g[u]
        g[u]-=g[v];
        size[u]-=size[v];
        f[u]-=f[v]+size[v];
        g[u]+=f[u]*num[u]+sum[u]*size[u];
        //鍐嶆洿鏂皏閲屽叧浜巙鐨勬墍鏈夊€?
        g[v]-=f[v]*num[v]+sum[v]*size[v];
        size[v]+=size[u];
        f[v]+=f[u]+size[u];
        g[v]+=g[u];
        g[v]+=f[v]*num[v]+sum[v]*size[v];

        DFS2(v,u);

        //鏀瑰彉鏈夊悜鏍戠粨鏋勶紝灏唘浣滀负v鐖朵翰锛屽厛鏇存柊v閲屽叧浜巙鐨勬墍鏈夊€?
        g[v]-=f[v]*num[v]+sum[v]*size[v];
        size[v]-=size[u];
        f[v]-=f[u]+size[u];
        g[v]-=g[u];
        g[v]+=f[v]*num[v]+sum[v]*size[v];
        //鍐嶆洿鏂皍閲屽叧浜巚鐨勬墍鏈夊€?
        g[u]-=f[u]*num[u]+sum[u]*size[u]; //閲嶇疆g[u]
        g[u]+=g[v];
        size[u]+=size[v];
        f[u]+=f[v]+size[v];
        g[u]+=f[u]*num[u]+sum[u]*size[u];
    }
}

int stack[MAXN],top=0;

int main()
{
    freopen("B.in","r",stdin);
    freopen("B.out","w",stdout);
    memset(head,-1,sizeof(head));
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        AddEdge(u,v);
        AddEdge(v,u);
    }
    for(int i=1;i<=m;i++)
    {
        int pos,val;
        scanf("%d%d",&pos,&val);
        num[pos]++,sum[pos]+=(LL)val;
    }
    DFS1(1,-1);
    DFS2(1,-1);
    LL minans=INF;
    for(int i=1;i<=n;i++)
        if(ans[i]<minans)
            minans=ans[i];
    for(int i=1;i<=n;i++)
        if(ans[i]==minans)
            stack[++top]=i;
    printf("%I64d\n",minans);
    for(int i=1;i<=top;i++)
        printf("%d ",stack[i]);
    printf("\n");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值