地址: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 */