Apple Tree
Posted ph = x
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Apple Tree相关的知识,希望对你有一定的参考价值。
题意:
给一有根树,每个叶子上有一些苹果,现在要求你拿掉一些苹果,使得每一个点的 儿子的子树内的苹果数相同。
解法:
首先可以发现$cnt$个叶子节点之间的关系可以用$cnt-1$个独立方程表示出来。
这样相当于在方程的解中只有一个变元。
接下来求出最小整数基底:这个我们可以两遍$dfs$ + $gcd$求出。
总效率$O(nlogn)$
#include <iostream> #include <cstdio> #include <cstring> #define LL long long #define N 100010 #define INF 0x3f3f3f3f3f3f3f3fLL using namespace std; struct edge { int x,to; }E[N<<1]; int n,totE; int g[N]; LL f[N],a[N],sum; bool is_leaf[N]; void addedge(int x,int y) { E[++totE] = (edge){y,g[x]}; g[x]=totE; E[++totE] = (edge){x,g[y]}; g[y]=totE; } LL gcd(LL a,LL b) { if(!b) return a; return gcd(b,a%b); } #define p E[i].x LL calc(int x,int tp) { int cnt=0; LL ans=1; for(int i=g[x];i;i=E[i].to) if(p!=tp) { LL tmp = calc(p,x); cnt++; if(ans/gcd(ans,tmp)<=sum/tmp) ans = ans/gcd(ans,tmp)*tmp; else return -1; } if(!cnt) { is_leaf[x]=1; return 1LL; } if(ans<=sum/cnt) return ans*(LL)cnt; else return -1; } void dfs(int x,int tp) { int cnt=0; for(int i=g[x];i;i=E[i].to) if(p!=tp) cnt++; for(int i=g[x];i;i=E[i].to) if(p!=tp) { f[p]=f[x]/(LL)cnt; dfs(p,x); } } int main() { while(~scanf("%d",&n)) { for(int i=1;i<=n;i++) g[i]=0,is_leaf[i]=0; totE=0; sum=0; for(int i=1;i<=n;i++) scanf("%I64d",&a[i]),sum+=a[i]; for(int i=1,x,y;i<n;i++) { scanf("%d%d",&x,&y); addedge(x,y); } f[1]=calc(1,1); if(f[1]==-1) { cout << sum << endl; continue; } dfs(1,1); LL t=INF, ans=0; for(int i=1;i<=n;i++) if(is_leaf[i]) { ans += a[i]; t = min(t, a[i]/f[i]); } ans -= t*f[1]; cout << ans << endl; } return 0; } /* t*A_i <= B_i(原先的) t <= B_i/A_i */
以上是关于Apple Tree的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces 930 A. Peculiar apple-tree (dfs)
POJ 3321:Apple Tree(dfs序+树状数组)