记录编号 291929 评测结果 AAAAAAAAAA
题目名称 [NOIP 2014]联合权值 最终得分 100
用户昵称 GravatarAntiLeaf 是否通过 通过
代码语言 C++ 运行时间 0.241 s
提交时间 2016-08-08 13:49:38 内存使用 7.81 MiB
显示代码纯文本
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=200010;
struct edge{
	int to,prev;
	edge():prev(0){}
}e[maxn<<1];
void insert(int,int);
void bfs();
void rebfs();
int len=0,last[maxn]={0};
int n,w[maxn],sum[maxn],mxa[maxn],mxb[maxn],prt[maxn],ans=0,mx=0,x,y;
int a[maxn],head=1,tail=1;//a既是模拟队列也是bfs序
int main(){
	freopen("linkb.in","r",stdin);
	freopen("linkb.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<n;i++){
		scanf("%d%d",&x,&y);
		insert(x,y);
		insert(y,x);
	}
	for(int i=1;i<=n;i++)scanf("%d",&w[i]);
	bfs();
	//printf("\n");
	rebfs();
	printf("%d %d",mx,(ans<<1)%10007);
	//printf("\n");
	//for(int i=1;i<=n;i++)printf("i=%d w=%d sum=%d mxa=%d mxb=%d\n",i,w[i],sum[i],mxa[i],mxb[i]);
	fclose(stdin);
	fclose(stdout);
	return 0;
}
void insert(int x,int y){
	e[++len].to=y;
	e[len].prev=last[x];
	last[x]=len;
}
void bfs(){
	int x,y;
	a[tail++]=1;
	while(head!=tail){
		x=a[head++];
		//printf("%d ",x);
		for(int i=last[x];i;i=e[i].prev){
			y=e[i].to;
			if(y==prt[x])continue;
			prt[y]=x;
			if(w[y]>mxa[x]){
				mxb[x]=mxa[x];
				mxa[x]=w[y];
			}
			else if(w[y]>mxb[x])mxb[x]=w[y];
			a[tail++]=y;
		}
	}
}
void rebfs(){
	int x;
	for(int i=n;i;i--){
		x=a[i];
		//printf("\nx=%d\n",x);
		ans+=sum[prt[x]]*w[x];
		ans%=10007;
		//printf("(bro)ans+=sum[%d](now%d)*w[%d](%d)=%d\n",prt[x],sum[prt[x]],x,w[x],sum[prt[x]]*w[x]);
		sum[prt[x]]+=w[x];
		sum[prt[x]]%=10007;
		ans+=sum[x]*w[prt[x]];
		ans%=10007;
		//printf("(prt)ans+=sum[%d](now%d)*w[%d](%d)=%d\n",x,sum[x],prt[x],w[prt[x]],sum[x]*w[prt[x]]);
		mx=max(mx,mxa[x]*mxb[x]);
		mx=max(mx,mxa[x]*w[prt[x]]);
	}
}
/*
5
1 2
2 3
3 4
4 5
1 5 2 3 10
Answer:
20 74
*/
/*
9
3 8
1 4
2 1
9 3
2 3
4 5
4 6
4 7
10 3 9 8 1 4 3 7 2
Answer:
90 508
*/
/*
解法:
不要被这个题吓到,暴力枚举是很费的。
与一个点距离为2只有三种情况:
1.它的父亲的父亲
2.它的儿子的儿子
3.它的兄弟
其中前两种情况只需求出一种即可(另一种会被这一种包括)。
为每个节点记录一个附加信息sum表示儿子的权和,
这样2就直接用它的权值乘上儿子的权和即可,
3利用sum也可以做到O(son)计算。
总时间复杂度应该是O(n)。
为了避免爆栈,这里采用bfs逆序处理(这样一定可以保证处理顺序是深度严格递减的)。
顺便一提并没有用到树剖和LCA什么的鬼东西。
至于求最大值,直接记录儿子中的最大权和次大权,比较最大权*父亲和最大权*次大权即可。
*/