描述

小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

统计所形成的三棵子树的节点权值之和能够两两相等的方案,等价于在这树上取两个不同且非根结点,形成三棵子树后子树节点权值之和两两相等。

树型dp求解,每个节点维护res(以这个节点为根的子树节点权值和),cnt(以这个节点为根的子树权值等于sum/3的节点个数)。

一开始能够想到的一个A节点res=sum/3,那么在这棵子树外再找一个res=sum/3的B节点进行组合不就得出一种方案了吗。可是这里面是分两类的

1.      B不是A的祖先,那么后来枚举B的时候A又被算了一次。记为2*s1

2.      B是A的祖先,其实这种情况是错误的,因为A、B分别取出后,A子树res=sum/3,B子树res=0(因为A子树本来就是B的一部分啊),这种方案是错误的要除去,且记为p

还有一种情况是一个节点res=sum*2/3,那么这个节点与其子树内不包括它自己,任意一个res=sum/3的节点相组合就是一种方案,记为s2。

因为不能选root,所以cnt对res[root]=sum/3情况不予考虑

2*s1+p=cnt[root]^2 - (res[x]=sum/3&&x!=root)

P= (cnt[x]>0&&res[x]=sum/3&&x!=root)

S2= (res[x]=sum*2/3&&x!=root)

最后ans=s1+s2

Dp时维护好数据最后求解即可

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+8;
vector<int> g[maxn];
int root;
ll sum;
ll res[maxn];
ll cnt[maxn];
ll a[maxn];
ll s2,s3,sig;void dfs(int x,int p){res[x]=a[x];cnt[x]=0;if(g[x].size()<=1){if(res[x]==sum)cnt[x]=1;sig+=cnt[x];//cout<<"xx="<<x<<" "<<sum<<" "<<res[x]<<" "<<cnt[x]<<endl;return ;}for(int i=0;i<g[x].size();i++){int u=g[x][i];if(u==p)continue;dfs(u,x);res[x]+=res[u];cnt[x]+=cnt[u];}if(res[x]==sum&&x!=root)cnt[x]+=1;if(res[x]==sum&&x!=root)sig+=cnt[x];if(cnt[x]>0&&res[x]==sum&&x!=root)s3+=(cnt[x]-1);if(res[x]==2*sum&&x!=root)s2+=(res[x]==sum?cnt[x]-1:cnt[x]);
}int main()
{int T;scanf("%d",&T);while(T--){int n;scanf("%d",&n);for(int i=0;i<n+7;i++)g[i].clear();sum=0;for(int i=1;i<=n;i++){int v,p;scanf("%d%d",&v,&p);a[i]=v;g[i].push_back(p);g[p].push_back(i);if(p==0)root=i;sum+=v;}if(sum%3){printf("0\n");continue;}sum/=3;s2=s3=sig=0;dfs(root,0);
//        for(int i=1;i<=n;i++){
//            printf("id==%d res==%I64d cnt==%I64d\n",i,res[i],cnt[i]);
//        }
//        cout<<" s2=="<<s2<<" s3=="<<s3<<" sig=="<<sig<<endl;ll ans=((cnt[root]*cnt[root]-sig)-s3)/2+s2;cout<<ans<<endl;}return 0;
}

hihocoder 1479 三等分 树型dp相关推荐

  1. 其他OJ 树型DP 选课

    在朱全民的PPT介绍的一个树型DP经典题,<选课>,中文题目,不结束 找了很久找到了可以提交的OJ,重庆八中 http://www.cqoi.net:2012/JudgeOnline/pr ...

  2. 【树型DP】BZOJ1564 二叉查找树(noi2009)

    标签: 二叉查找树 [题目描述] 已知一棵特殊的二叉查找树.根据定义,该二叉查找树中每个结点的数据值都比它左儿子结点的数据值大,而比它右儿子结点的数据值小. 另一方面,这棵查找树中每个结点都有一个权值 ...

  3. 【树型DP】加分二叉树

    问题 b: [树型DP]加分二叉树 时间限制: 1 Sec  内存限制: 64 MB 提交: 8  解决: 6 [提交] [状态] [讨论版] [命题人:admin] 题目描述 科技忽略了过程就是魔法 ...

  4. 二叉苹果树(树型DP+背包)

    二叉苹果树 有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点).这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1. 我们用一根树枝两端连接的结点的编号 ...

  5. POJ3342 Party at Hali-Bula(树型DP求最大独立集+唯一解判断)

    题意: 公司参加聚会,要求员工不能和他的上司同时参加,求最多能参加几个人并且判断解是否唯一. 要点: 树型DP的经典题,用dp[u][1]表示选取u的最大值,dp[u][0]表示不选取u的最大值,容易 ...

  6. 虚树+树型DP SDOI2011消耗战

    <虚树+树型DP> SDOI2011消耗战 #include <iostream> #include <cstdio> #include <cstring&g ...

  7. BSOJ 2923:藤原妹红 MST+树型DP

    2923 -- [模拟试题]藤原妹红 Description 在幻想乡,藤原妹红是拥有不老不死能力的人类.虽然不喜欢与人们交流,妹红仍然保护着误入迷途竹林村民.由于妹红算得上是幻想乡最强的人类,对于她 ...

  8. 洛谷P3354 Riv河流 [IOI2005] 树型dp

    正解:树型dp 解题报告: 传送门! 简要题意:有棵树,每个节点有个权值w,要求选k个节点,最大化∑dis*w,其中如果某个节点到根的路径上选了别的节点,dis指的是到达那个节点的距离 首先这个一看就 ...

  9. 蓝桥杯:生命之树【树型dp】

    之前本菜还没学树型dp的时候,下意识地认为这个东西很难,感觉这个东西结合了搜索+dp这两座算法界的大山必定很难,但万万没想到啊,这个东西很像我之前讲的记忆化搜索,甚至我认为,记忆化搜索的一个作用就是将 ...

最新文章

  1. 【BZOJ3314】 [Usaco2013 Nov]Crowded Cows 单调队列
  2. STM32串口实时接收数据与所提前定义的比较,并作出相应的操作
  3. 中国牡蛎碳酸钙市场需求现状调研及十四五投资风险评估报告2022-2028年版
  4. 配置MySQL5.7基于keepalived的GTID的双主复制
  5. socket通信中的几个重要结构体定义
  6. mac上用qt调用自己生成的qt动态库,该动态库又依赖第三方库
  7. 等保制度与ISO27001的区别与联系
  8. sap未分摊差异怎么处理_物料主数据价格控制及差异问题
  9. 清明档总票房仅1.2亿元 全国影院营业比例不足50%
  10. CTF-Mayday
  11. MySQL双主机双Master方案测试
  12. 微信小程序在线考试项目开发-用户授权登录、身份信息获取
  13. Python学习之路-爬虫(四大名著)
  14. 平均增长率不用计算机,【程阳解答】如何用计算器或Excel计算年均增长率?
  15. ps——霓虹灯字体效果
  16. C语言如何编程换算小时秒,小时分钟秒的换算(c语言把时间转换成秒)
  17. Django项目QQ登录后端接口实现
  18. 求次方的c语言程序,C语言编程求13的13次方的最后三位数
  19. java kafka设置偏移量_kafka实战宝典:手动修改消费偏移量的两种方式
  20. Diagnosing OSGi uses conflicts

热门文章

  1. VR城市街景让用户全面地了解城市状况
  2. 《逆商》我们该如何应对坏事件
  3. NEUQ-ACM预备队训练-week8(背包)
  4. Ultra96-V2 板子通信
  5. 通过写一个C++程序实现,通过ROS系统的serious包打开串口并获得数据
  6. (转)什么妨碍我们进步
  7. 一个《跳动的爱心》代码,纯HTML+JS,双击直接运行
  8. 深度之眼(九)——python函数--面向过程的编程
  9. 09 Marr算子(LoG算法)
  10. NVIDIA TX2刷ubuntu16.04、刷设备树教程