zoukankan      html  css  js  c++  java
  • hihocoder1479 三等分

    地址:http://hihocoder.com/problemset/problem/1479

    题目:

    三等分

    时间限制:10000ms
    单点时限:1000ms
    内存限制:256MB

    描述

    小Hi最近参加了一场比赛,这场比赛中小Hi被要求将一棵树拆成3份,使得每一份中所有节点的权值和相等。

    比赛结束后,小Hi发现虽然大家得到的树几乎一模一样,但是每个人的方法都有所不同。于是小Hi希望知道,对于一棵给定的有根树,在选取其中2个非根节点并将它们与它们的父亲节点分开后,所形成的三棵子树的节点权值之和能够两两相等的方案有多少种。

    两种方案被看做不同的方案,当且仅当形成方案的2个节点不完全相同。

    输入

    每个输入文件包含多组输入,在输入的第一行为一个整数T,表示数据的组数。

    每组输入的第一行为一个整数N,表示给出的这棵树的节点数。

    接下来N行,依次描述结点1~N,其中第i行为两个整数Vi和Pi,分别描述这个节点的权值和其父亲节点的编号。

    父亲节点编号为0的节点为这棵树的根节点。

    对于30%的数据,满足3<=N<=100

    对于100%的数据,满足3<=N<=100000, |Vi|<=100, T<=10

    输出

    对于每组输入,输出一行Ans,表示方案的数量。

    样例输入
    2
    3
    1 0
    1 1
    1 2
    4
    1 0
    1 1
    1 2
    1 3
    样例输出
    1
    0
    思路:哈希+dfs
    两遍dfs,第一遍求出到该点的权值和(sum[x]:权值和),第二遍时计算答案ans。
    因为只有三等分,其中一个点已经规定了是根节点,所以只需考虑剩下两个点(选作根)的情况:
    1.两个点是祖先关系,两点在同一条链上。
    2.两点不在同一条链上。
    对于这两种情况,我们可以两个哈希来解决
    对于第一种情况:维护一个map<int,int>fa的哈希,该哈希记录的是到节点x的所有祖先节点的权值和,则可以三等分时有sum[root]==3*sum[x]?ans+=fa[2*sum[x]]:0;
    对于第二种情况:同样是维护一个哈希map<int,int>hs,该哈希记录的是除节点的x的祖先节点外已dfs过的节点的权值和,则可以三等分时有sum[root]==3*sum[x]?ans+=hs[sum[x]]:0;
    综上:
    if(sum[root]==3*sum[x])
      ans+=fa[2*sum[x]]+hs[sum[x]];

    另外一种做法,dp!
    dp[x][i]:表示到节点x时,合法的i等分的情况有多少种。
    然后考虑下子树合并时的情况就好了。
    这种方法可以解决n等分问题,第一种方法不能。
     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 #define MP make_pair
     6 #define PB push_back
     7 typedef long long LL;
     8 typedef pair<int,int> PII;
     9 const double eps=1e-8;
    10 const double pi=acos(-1.0);
    11 const int K=1e6+7;
    12 const int mod=1e9+7;
    13 
    14 int n,v[100005],sum[100005];
    15 vector<int>mp[100005];
    16 map<int,int>hs,fa;
    17 LL ans;
    18 void dfs1(int x)
    19 {
    20     sum[x]=v[x];
    21     for(int i=0;i<mp[x].size();i++)
    22         dfs1(mp[x][i]),sum[x]+=sum[mp[x][i]];
    23 }
    24 void dfs2(int x,int f)
    25 {
    26     if(x!=f&&sum[f]==3*sum[x])    ans+=fa[sum[x]*2]+hs[sum[x]];
    27     if(x!=f)fa[sum[x]]++;
    28     for(int i=0;i<mp[x].size();i++)
    29     {
    30         int u=mp[x][i];
    31         dfs2(u,f),hs[sum[u]]++;
    32     }
    33     if(x!=f)fa[sum[x]]--;
    34 }
    35 int main(void)
    36 {
    37     int t;cin>>t;
    38     while(t--)
    39     {
    40         ans=0;
    41         memset(sum,0,sizeof(sum));
    42         hs.clear(),fa.clear();
    43         memset(mp,0,sizeof(mp));
    44         cin>>n;
    45         for(int i=1,x;i<=n;i++)
    46             scanf("%d%d",&v[i],&x),mp[x].PB(i);
    47         dfs1(mp[0][0]);
    48         if(sum[mp[0][0]]%3==0)
    49             dfs2(mp[0][0],mp[0][0]);
    50         cout<<ans<<endl;
    51     }
    52     return 0;
    53 }
    54 /*
    55 123
    56 13
    57 0 0
    58 -1 1
    59 1 2
    60 -1 3
    61 1 4
    62 -1 5
    63 1 6
    64 -1 1
    65 1 8
    66 -1 9
    67 1 10
    68 -1 11
    69 1 12
    70 7
    71 0 0
    72 0 1
    73 0 2
    74 0 3
    75 0 1
    76 0 5
    77 0 6
    78 5
    79 0 0
    80 0 1
    81 0 1
    82 0 1
    83 0 1
    84 9
    85 0 0
    86 0 1
    87 0 2
    88 0 1
    89 0 4
    90 0 1
    91 0 6
    92 0 1
    93 0 8
    94 */

     

     
  • 相关阅读:
    【EF学习笔记11】----------查询中常用的扩展方法
    .NET 扩展方法
    【EF学习笔记10】----------主从表级联操作
    【EF学习笔记09】----------使用 EntityState 枚举标记实体状态,实现增删改查
    【EF学习笔记08】----------加载关联表的数据 显式加载
    【EF学习笔记07】----------加载关联表的数据 贪婪加载
    【EF学习笔记06】----------加载关联表的数据 延迟加载
    Linux内核ROP姿势详解(二)
    见微知著(三):解析ctf中的pwn--Fastbin和bins的溢出
    见微知著(二):解析ctf中的pwn--怎么利用double free
  • 原文地址:https://www.cnblogs.com/weeping/p/6541520.html
Copyright © 2011-2022 走看看