noip 联合权值
暴力做法:枚举每个节点与它距离为二的点,
正解:距离为二的点只有两种情况。
1.某个叶子节点与它父亲的父亲。
2.某一个父亲的两个儿子。
对于1,枚举每个点父亲的父亲。
2.x1x2+x2x3+x1x3=1/2*[(x1+x2+x3)^2-x1^2-x2^2-x3^2]
统计某个父亲节点的儿子点权和,点权平方和。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; const long long mo=10007,N=2e5+300; struct re{ long long v; long long nex; }; re edge[2*N]; long long dep[N],fa[N],ans,n,d[N],f[N],tot,maxer=0; void ad(long long x,long long y){ tot++; edge[tot].nex=f[x]; edge[tot].v=y; f[x]=tot; } void dfs(long long fath,long long son){ bool az=1; long long k=f[son],az1,m1=0,m2=0; long long s=0,p=0; while(k!=-1){ long long x=edge[k].v; if(x!=fath){ az=0; s=(s+d[x])%mo; p=(p+d[x]*d[x])%mo; if(d[x]>m1){m2=m1;m1=d[x];} else if(d[x]>m2)m2=d[x];} k=edge[k].nex; } if(az)return ; long long ax; ax=s*s-p; az1=m1*m2; maxer=max(maxer,az1); while(ax<0)ax+=mo; ans+=ax; k=f[son]; while(k!=-1){ long long x=edge[k].v; if(x!=fath)dfs(son,x); k=edge[k].nex; } } void js(long long fath,long long son){ dep[son]=dep[fath]+1; fa[son]=fath; long long k=f[son]; while(k!=-1){ long long x=edge[k].v; if(!dep[x])js(son,x); k=edge[k].nex; } } int main() { //freopen("p.in","r",stdin); memset(f,-1,sizeof(f)); cin>>n; for(long long i=1;i<n;i++) {long long a,b; cin>>a>>b; ad(a,b); ad(b,a); } for(long long i=1;i<=n;i++)cin>>d[i]; long long jsdlkjl; dfs(0,1); js(0,1); for(long long i=1;i<=n;i++) if(dep[i]>=3){ long long tmp; tmp=d[fa[fa[i]]]; maxer=max(maxer,tmp*d[i]); ans=(ans+tmp*d[i]*2)%mo; } cout<<maxer<<' '<<ans; return 0; }
戒骄戒躁