zoukankan      html  css  js  c++  java
  • 第四届西安邮电大学acm-icpc校赛 热狗树

    题目描述

     “我是番茄酱!”
    “我是黄芥末酱!”
    “合在一起就是——美式热狗上加的,那个!“
    热狗树上的每个节点都涂有番茄酱或者黄芥末酱中的一种,这样热狗树就变得美味了~LiMn2O4构造了一颗热狗树,他想知道这棵树的美味程度。
    一个热狗树的美味程度,定义为每个节点到其他和自己口味不一样的节点的最短距离之和的和,也就是任意两个口味不同的节点之间的路径长度和。请你求出这颗树的美味值,并且答案对998244353取模。
     

    输入

    第一行一个正整数N。
    第二行有N个数,他们的值在[0,1]范围内取,其中1代表是涂了番茄酱,0代表是涂了黄芥末酱。
    接下来N-1行,每一行有三个数a,b,w。代表节点a到b有边,路径的权值是w。输入数据保证是一棵树。
    N≤100000,1≤a,b≤N,w<1 000 000 000
     

    输出

    输出答案对998244353取模后的结果。

    样例输入

    3
    1 0 1
    1 2 1
    1 3 2
    

    样例输出

    8
    

    提示

    树(tree)是包含n(n>=0)个结点的有穷集,其中:
    (1)每个元素称为结点(node);
    (2)有一个特定的结点被称为根结点或树根(root)。
    (3)除根结点之外的其余数据元素被分为m(m≥0)个互不相交的集合T1,T2,……Tm-1,其中每一个集合Ti(1<=i<=m)本身也是一棵树,被称作原树的子树(subtree)。

       很裸的一个树形dp,sb的一直在用点算,其实直接以边的角度来看,每条边的贡献值就是,2ll*(子节点子树为1的数目*(总0数目-子节点子树为0的数目)*边权+子节点子树为0的数目*(总1数目-子节点子树为1的数目)*边权)

      也就是看这条边两边为0和为1的情况。

     1 #include<cstdio>
     2 typedef long long ll;
     3 const int N=100118,mod=998244353;
     4 struct Side{
     5     int v,ne;
     6     ll w;
     7 }S[N<<1];
     8 int sn,head[N],size[N][2],a[N],num[2];
     9 ll ans;
    10 void init(int n)
    11 {
    12     sn=0;
    13     ans=0;
    14     num[0]=num[1]=0;
    15     for(int i=0;i<=n;i++){
    16         head[i]=-1;
    17         size[i][0]=size[i][1]=0;
    18     }
    19 }
    20 void add(int u,int v,int w)
    21 {
    22     S[sn].v=v;
    23     S[sn].w=1ll*w;
    24     S[sn].ne=head[u];
    25     head[u]=sn++;
    26 }
    27 void dfs(int u,int f)
    28 {
    29     size[u][0]=(a[u]==0);
    30     size[u][1]=(a[u]==1);
    31     for(int i=head[u],v;~i;i=S[i].ne){
    32         v=S[i].v;
    33         if(v!=f){
    34             dfs(v,u);
    35             size[u][0]+=size[v][0];
    36             size[u][1]+=size[v][1];
    37             ans=(ans+2ll*size[v][0]*(num[1]-size[v][1])*S[i].w%mod)%mod;
    38             ans=(ans+2ll*size[v][1]*(num[0]-size[v][0])*S[i].w%mod)%mod;
    39         }
    40     }
    41 }
    42 int main()
    43 {
    44     int n,u,v,w;
    45     while(~scanf("%d",&n)){
    46         init(n);
    47         for(int i=1;i<=n;i++){
    48             scanf("%d",&a[i]);
    49             num[0]+=(a[i]==0);
    50             num[1]+=(a[i]==1);
    51         }
    52         for(int i=1;i<n;i++){
    53             scanf("%d%d%d",&u,&v,&w);
    54             add(u,v,w);
    55             add(v,u,w);
    56         }
    57         dfs(1,0);
    58         printf("%lld
    ",ans);
    59     }
    60     return 0;
    61 }
    看边啊
  • 相关阅读:
    C# 系统应用之通过注册表获取USB使用记录(一)
    web项目测试方法总结
    C#面向对象编程实例-猜拳游戏
    c#基础这些你都看过吗?(一)-----仅供初学者使用
    .NET事件监听机制的局限与扩展
    SQL代码
    泛型接口委托
    存储过程
    小操作
    DataGridView
  • 原文地址:https://www.cnblogs.com/LMCC1108/p/11115202.html
Copyright © 2011-2022 走看看