hihocoder 1479 三等分 树型dp
-
描述
小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相关推荐
- 其他OJ 树型DP 选课
在朱全民的PPT介绍的一个树型DP经典题,<选课>,中文题目,不结束 找了很久找到了可以提交的OJ,重庆八中 http://www.cqoi.net:2012/JudgeOnline/pr ...
- 【树型DP】BZOJ1564 二叉查找树(noi2009)
标签: 二叉查找树 [题目描述] 已知一棵特殊的二叉查找树.根据定义,该二叉查找树中每个结点的数据值都比它左儿子结点的数据值大,而比它右儿子结点的数据值小. 另一方面,这棵查找树中每个结点都有一个权值 ...
- 【树型DP】加分二叉树
问题 b: [树型DP]加分二叉树 时间限制: 1 Sec 内存限制: 64 MB 提交: 8 解决: 6 [提交] [状态] [讨论版] [命题人:admin] 题目描述 科技忽略了过程就是魔法 ...
- 二叉苹果树(树型DP+背包)
二叉苹果树 有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点).这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1. 我们用一根树枝两端连接的结点的编号 ...
- POJ3342 Party at Hali-Bula(树型DP求最大独立集+唯一解判断)
题意: 公司参加聚会,要求员工不能和他的上司同时参加,求最多能参加几个人并且判断解是否唯一. 要点: 树型DP的经典题,用dp[u][1]表示选取u的最大值,dp[u][0]表示不选取u的最大值,容易 ...
- 虚树+树型DP SDOI2011消耗战
<虚树+树型DP> SDOI2011消耗战 #include <iostream> #include <cstdio> #include <cstring&g ...
- BSOJ 2923:藤原妹红 MST+树型DP
2923 -- [模拟试题]藤原妹红 Description 在幻想乡,藤原妹红是拥有不老不死能力的人类.虽然不喜欢与人们交流,妹红仍然保护着误入迷途竹林村民.由于妹红算得上是幻想乡最强的人类,对于她 ...
- 洛谷P3354 Riv河流 [IOI2005] 树型dp
正解:树型dp 解题报告: 传送门! 简要题意:有棵树,每个节点有个权值w,要求选k个节点,最大化∑dis*w,其中如果某个节点到根的路径上选了别的节点,dis指的是到达那个节点的距离 首先这个一看就 ...
- 蓝桥杯:生命之树【树型dp】
之前本菜还没学树型dp的时候,下意识地认为这个东西很难,感觉这个东西结合了搜索+dp这两座算法界的大山必定很难,但万万没想到啊,这个东西很像我之前讲的记忆化搜索,甚至我认为,记忆化搜索的一个作用就是将 ...
最新文章
- 【BZOJ3314】 [Usaco2013 Nov]Crowded Cows 单调队列
- STM32串口实时接收数据与所提前定义的比较,并作出相应的操作
- 中国牡蛎碳酸钙市场需求现状调研及十四五投资风险评估报告2022-2028年版
- 配置MySQL5.7基于keepalived的GTID的双主复制
- socket通信中的几个重要结构体定义
- mac上用qt调用自己生成的qt动态库,该动态库又依赖第三方库
- 等保制度与ISO27001的区别与联系
- sap未分摊差异怎么处理_物料主数据价格控制及差异问题
- 清明档总票房仅1.2亿元 全国影院营业比例不足50%
- CTF-Mayday
- MySQL双主机双Master方案测试
- 微信小程序在线考试项目开发-用户授权登录、身份信息获取
- Python学习之路-爬虫(四大名著)
- 平均增长率不用计算机,【程阳解答】如何用计算器或Excel计算年均增长率?
- ps——霓虹灯字体效果
- C语言如何编程换算小时秒,小时分钟秒的换算(c语言把时间转换成秒)
- Django项目QQ登录后端接口实现
- 求次方的c语言程序,C语言编程求13的13次方的最后三位数
- java kafka设置偏移量_kafka实战宝典:手动修改消费偏移量的两种方式
- Diagnosing OSGi uses conflicts