/* 一开始的思路 求出每两个点之间的距离(其实枚举两个点就T了) 统计为2 的点对 然后统计答案 倍增LCA的话 是O(n+n*n) 后面的n*n是枚举那两个点 华丽的T了 60分 */ #include<iostream> #include<cstdio> #include<cstring> #define maxn 200010 using namespace std; int n,w[maxn],fa[maxn][20],head[maxn],num,dep[maxn],ans,sum; struct node { int u,v,pre; }e[maxn*2]; int init() { int x=0;char s=getchar(); while(s<‘0‘||s>‘9‘)s=getchar(); while(s>=‘0‘&&s<=‘9‘){x=x*10+s-‘0‘;s=getchar();} return x; } void Add(int from,int to) { num++; e[num].u=from; e[num].v=to; e[num].pre=head[from]; head[from]=num; } void Dfs(int now,int from,int c) { fa[now][0]=from; dep[now]=c; for(int i=head[now];i;i=e[i].pre) if(e[i].v!=from) Dfs(e[i].v,now,c+1); } void Get_fa() { for(int j=1;j<=17;j++) for(int i=1;i<=n;i++) fa[i][j]=fa[fa[i][j-1]][j-1]; } int Get_a(int a,int t) { for(int i=1;i<=t;i++) a=fa[a][0]; return a; } int LCA(int a,int b) { if(dep[a]<dep[b])swap(a,b); a=Get_a(a,dep[a]-dep[b]); if(a==b)return a; for(int i=17;i>=0;i--) if(fa[a][i]!=fa[b][i]) { a=fa[a][i]; b=fa[b][i]; } return fa[a][0]; } int main() { //freopen("linkb.in","r",stdin); //freopen("linkb.out","w",stdout); n=init(); int u,v; for(int i=1;i<=n-1;i++) { u=init();v=init(); Add(u,v);Add(v,u); } for(int i=1;i<=n;i++) w[i]=init(); Dfs(1,1,0); Get_fa(); for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) { int anc=LCA(i,j); int deep=dep[i]+dep[j]-2*dep[anc]; if(deep==2) { ans=max(ans,w[i]*w[j]); sum=(sum+w[i]*w[j])%10007; } } printf("%d %d\n",ans,sum*2%10007); return 0; }
/* 因为默认的边权值是1 所以距离为2的点也就是从同一个点出发的两个 这样我们不需要n*n的枚举点 我们统计每个点之间相连的 然后两两组合 这里会发现 又跑慢了 70分 假设点x直接相连的点有三个 权值分别是a b c 那么我们两两组合后总权值是ab+bc+ac 会发现这里和之前用线段树求区间两两元素之和是一样的 根据数学公式 (a+b+c)^2-a^2-b^2-c^2=2*(ab+bc+ac) 这样我们就可以很快地求出权值和 至于最大的嘛 那肯定是最大的两个点权之积 */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 200010 #define mod 10007 using namespace std; int n,w[maxn],head[maxn],num,ans,sum; struct node { int u,v,pre; }e[maxn*2]; int cmp(int x,int y) { return x>y; } int init() { int x=0;char s=getchar(); while(s<‘0‘||s>‘9‘)s=getchar(); while(s>=‘0‘&&s<=‘9‘){x=x*10+s-‘0‘;s=getchar();} return x; } void Add(int from,int to) { num++; e[num].u=from; e[num].v=to; e[num].pre=head[from]; head[from]=num; } int main() { //freopen("linkb.in","r",stdin); //freopen("linkb.out","w",stdout); n=init(); int x,y; for(int i=1;i<=n-1;i++) { x=init();y=init(); Add(x,y);Add(y,x); } for(int i=1;i<=n;i++) w[i]=init(); for(int u=1;u<=n;u++) { int p[maxn],l=0,tmp=0,s=0; for(int i=head[u];i;i=e[i].pre) p[++l]=w[e[i].v]; sort(p+1,p+1+l,cmp); ans=max(ans,p[1]*p[2]); for(int i=1;i<=l;i++) { tmp=(tmp+p[i]*p[i]%mod)%mod; s=(s+p[i]%mod)%mod; } sum=(sum+(s*s-tmp)%mod)%mod; } printf("%d %d\n",ans,sum); return 0; }
时间: 2024-10-09 05:23:37