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

#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
参考博客:http://blog.csdn.net/viphong/article/details/61958631
需要两个dfs,第一个dfs从父节点开始递归遍历,求出以每个节点为根的子树的权值和。
第二个dfs就是开始统计个数: 若某一节点正好是总数的1/3,那么该节点很有可能和另一个节点符合题目要求,那么另一个节点就是另一个1/3节点,或者另一个节点是该节点祖先节点,这个祖先节点是总数的2/3
 #include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
const int Max = + ;
int v[Max], sum[Max];
long long all, first, second, cnt, root;
vector<int> mp[Max];
//统计每个子树的权值和
void dfs(int node, int fa)
{
sum[node] = v[node];
for (int i = ; i < (int)mp[node].size(); i++)
{
int son = mp[node][i];
if (son != fa)
{
dfs(son, node);
sum[node] += sum[son];
}
}
}
// 核心
void dfs2(int node, int fa)
{
//找到一个1/3节点
if (sum[node] == all)
cnt += first + second;
// 因为可能有负数,所有要继续往下递归
if (sum[node] == all * && node != root)
second++; for (int i = ; i < (int)mp[node].size(); i++)
{
int son = mp[node][i];
if (son != fa)
{
dfs2(son, node);
}
}
//每一个1/3的节点只会和另一个不同分支的1/3节点满足条件
//每一个1/3的节点只会和它祖先是2/3的满足条件
if (sum[node] == all)
first++;
//以node为根节点满足2/3,全都遍历完毕,所以再不存在以node为根与一个1/3节点满足条件,故删除该2/3节点
if (sum[node] == all * && node != root)
second--;
}
int main()
{
int n, t, fa;
scanf("%d", &t);
while (t--)
{
scanf("%d", &n);
//清空
for (int i = ; i <= n; i++)
mp[i].clear();
memset(sum, , sizeof(sum));
cnt = all = first = second = ;
for (int i = ; i <= n; i++)
{
scanf("%d%d", &v[i], &fa);
all += v[i];
if (fa == )
root = i;
mp[fa].push_back(i);
}
if (all % )
{
printf("0\n");
continue;
}
all /= ;
dfs(root, );
dfs2(root, );
printf("%lld\n", cnt);
}
return ;
}

#1479 : 三等分(树形DP)的更多相关文章

  1. Hihocoder #1479 : 三等分 树形DP

    三等分  描述 小Hi最近参加了一场比赛,这场比赛中小Hi被要求将一棵树拆成3份,使得每一份中所有节点的权值和相等. 比赛结束后,小Hi发现虽然大家得到的树几乎一模一样,但是每个人的方法都有所不同.于 ...

  2. SPOJ 1479 +SPOJ 666 无向树最小点覆盖 ,第二题要方案数,树形dp

    题意:求一颗无向树的最小点覆盖. 本来一看是最小点覆盖,直接一下敲了二分图求最小割,TLE. 树形DP,叫的这么玄乎,本来是线性DP是线上往前\后推,而树形DP就是在树上,由叶子结点状态向根状态推. ...

  3. poj3417 LCA + 树形dp

    Network Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4478   Accepted: 1292 Descripti ...

  4. COGS 2532. [HZOI 2016]树之美 树形dp

    可以发现这道题的数据范围有些奇怪,为毛n辣么大,而k只有10 我们从树形dp的角度来考虑这个问题. 如果我们设f[x][k]表示与x距离为k的点的数量,那么我们可以O(1)回答一个询问 可是这样的话d ...

  5. 【BZOJ-4726】Sabota? 树形DP

    4726: [POI2017]Sabota? Time Limit: 20 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 128  Solved ...

  6. 树形DP+DFS序+树状数组 HDOJ 5293 Tree chain problem(树链问题)

    题目链接 题意: 有n个点的一棵树.其中树上有m条已知的链,每条链有一个权值.从中选出任意个不相交的链使得链的权值和最大. 思路: 树形DP.设dp[i]表示i的子树下的最优权值和,sum[i]表示不 ...

  7. 树形DP

    切题ing!!!!! HDU  2196 Anniversary party 经典树形DP,以前写的太搓了,终于学会简单写法了.... #include <iostream> #inclu ...

  8. BZOJ 2286 消耗战 (虚树+树形DP)

    给出一个n节点的无向树,每条边都有一个边权,给出m个询问,每个询问询问ki个点,问切掉一些边后使得这些顶点无法与顶点1连接.最少的边权和是多少.(n<=250000,sigma(ki)<= ...

  9. POJ2342 树形dp

    原题:http://poj.org/problem?id=2342 树形dp入门题. 我们让dp[i][0]表示第i个人不去,dp[i][1]表示第i个人去 ,根据题意我们可以很容易的得到如下递推公式 ...

随机推荐

  1. Nginx 完整安装篇

    第一步安装各种编译库如c++编译库等 yum install -y gcc //安装GCC ...安装过程省略 yum install -y gcc-c++ //安装C++库用来编译c++ ...安装 ...

  2. Nginx 多核cpu负载均衡

    L:122 查看Linux CPU 缓存大小 cat /sys/devices/system/cpu/cpu1/cache/index0/size //指令缓存 cat /sys/devices/sy ...

  3. 数据库管理 trove openstack

    Trove是数据库即服务的OpenStack.它旨在完全基于OpenStack运行,其目标是允许用户快速轻松地利用关系数据库的功能,而无需处理复杂的管理任务.云用户和数据库管理员可以根据需要配置和管理 ...

  4. puppet一个完整的实例

    一个具体实例来简单说明puppet的具体结构 创建第一个配置 puppet的组成清单这主要包含这几个部分 资源,文件,模板,节点,类,定义 puppet中有个模块的定义,这个比较重要,基本是puppe ...

  5. eolinker——添加项目成员

    https://help.eolinker.com/account/?target=/md/workspace/team 在工作空间的主页面,而不是接口的主页面这个一定要注意,邀请方式有两种,根据自己 ...

  6. Tarjan求强连通分量,缩点,割点

    Tarjan算法是由美国著名计算机专家发明的,其主要特点就是可以求强连通分量和缩点·割点. 而强联通分量便是在一个图中如果有一个子图,且这个子图中所有的点都可以相互到达,这个子图便是一个强连通分量,并 ...

  7. Ionic3 新增 Service

    service是单例模式的 新增Service类 search.service.ts import {Injectable} from '@angular/core'; @Injectable() e ...

  8. MT【270】含参绝对值函数最大之二

    已知$f(x)=2ax\cos^2x+(a-1)\cos x-1,a>0$,记$|f(x)|$的最大值为$A$,1)求A.2)证明:$|-2a\sin 2x+(1-a)\sin x|\le 2A ...

  9. php获取用户真实IP和防刷机制

      一. 如何获取用户IP地址 public static function getClientIp() { if (getenv('HTTP_CLIENT_IP')) { $ip = getenv( ...

  10. python3 元组tuple

    元组应小括号()表示: tuple(seq)将列表转换为一个元组: 不可变的,元组是不可变,但元素可以是可变数据类型: 可以迭代,可以切片: +连接元组,*复制元组: del不可以删除元素,但可以删除 ...