【NOIP2013模拟11.6A组】灵能矩阵(pylon)

在这里插入图片描述
时间有保证,空间也不大(第一页第一个)
好了,说回正题
一看样例,感觉好像就是个裸的dfs,但在打代码的时候发现有毒。。。
比如说一个非叶子节点i,如果它要散逸能量的话一定要散逸son[i]的倍数,那样的话:
这个数据:
10
0 0 0 3 3 3 2 2 2 2
1 2
1 3
2 4
2 5
2 6
3 7
3 8
3 9
3 10
我们可以发现这题的正确答案应该是0
所以gg了,重新想(努力思考中。。。)
考场想着用堆来解决此问题,但发现不但T掉还会WA o(╥﹏╥)o,表示无奈。
经过研究发现,对于一个非叶子节点x,它的所有儿子节点都要小于等于它的最小的那个儿子节点。
然后,我们需要找出一个m——也就是每个儿子是值。因为要满足它的儿子节点相同且符合,那么我们可以设一个l[x]表示x的儿子的lcm。l[x]=lcm(son[x])*x的儿子个数。那么m=mi-mi mod (l[x]/儿子的个数)。

上标:

#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
struct node{int v,fr;}e[200010];
int n,tail[100010],son[100010],cnt=0,top=0;
ll ans=0,a[100010],l[100010];

inline int read()
{
	int x=0; char c=getchar();
	while (c<'0' || c>'9') c=getchar();
	while (c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x;
}

void add(int u,int v) {e[++cnt]=(node){v,tail[u]}; tail[u]=cnt;}

ll gcd(ll x,ll y) {return !y ? x:gcd(y,x%y);}

void dfs(int x,int fa)
{
	l[x]=1;if (!son[x]) return;
	ll mi=(ll)(1<<30)*(1<<30),s=0;
	for (int p=tail[x],v;p;p=e[p].fr)
		if ((v=e[p].v)!=fa)
		{
			dfs(v,x);s+=a[v];
			l[x]=l[x]*l[v]/gcd(l[x],l[v]);
			mi=min(mi,a[v]);
		}
	a[x]=(mi-mi%l[x])*son[x];
	l[x]*=son[x];ans+=s-a[x];
}

int main()
{
	freopen("pylon.in","r",stdin);
	freopen("pylon.out","w",stdout);
	n=read();
	for (int i=1;i<=n;i++) a[i]=read(),son[i]=-1;
 	for (int i=1,u,v;i<n;i++)
		u=read(),v=read(),add(u,v),add(v,u),son[u]++,son[v]++;
	son[1]++;dfs(1,0);
	printf("%lld\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Larry1118/article/details/85206872
今日推荐