题目(vijos)
这题一开始稍微想复杂了......
其实思考一下就明白,距离为2的两个点之间一定有一个点(废话),
于是我们反过来想:连接在一个点上的不同的两个点一定距离为2。
所以,这题可以这样:
枚举每一个点,把连接在这个点上的点的权值用一个d数组记录下来。
然后对d数组从大到小排序,这样第一题就解决了:ans1=max(ans1,d[1]*d[2])。
第二问采用前缀和的方式解决:
比如连接在同一个点上的点的权值分别为1,3,5,6,
假设我们不考虑有序数对,那么总和为1*(3+5+6)+3*(5+6)+5*6,
明显可以用前缀和来优化。
答案为sum*2。
这题就解决了~
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> #include <queue> using namespace std; typedef long long ll; template <class ___E> inline void read(___E &e) { e=0;bool ck=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')ck=1;ch=getchar();} while(ch>='0'&&ch<='9'){e=e*10+ch-'0';ch=getchar();} if(ck) e = -e; } const int mod=10007; struct edge{ int vk; int next; }e[400005]; int a[200005]; int d[200005]; int sum; int maxn; ll s[200005]; int n,m; int head[200005],t=1; bool cmp(const int &x,const int &y) { return x>y; } void ad(int u,int v) { e[t].vk=v; e[t].next=head[u]; head[u]=t++; } int main() { read(n); for (register int i=1;i<n;++i) { int x,y; read(x); read(y); ad(x,y); ad(y,x); } for (register int i=1;i<=n;++i) { read(a[i]); } int cnt=0; for (register int k=1;k<=n;++k) { for (int i=1;i<=cnt;++i) { d[i]=0; s[i]=0; } cnt=0; for (int i=head[k];i;i=e[i].next) { ++cnt; int v=e[i].vk; d[cnt]=a[v]; } if (cnt==1) continue; sort(d+1,d+cnt+1,cmp); maxn=max(maxn,d[1]*d[2]); for (int i=1;i<=cnt;++i) s[i]=s[i-1]+d[i]; for (int i=1;i<cnt;++i) { sum=sum+(((d[i su } } printf( return 0; }
Comments NOTHING