标签:超时 pac 自己 name space 树形结构 cto clu its
对于每一个点,所有与这个点相连的其他点构成一个集合,这个集合内任意两个点的距离为2。
很自然地在建图的过程中得到这些集合。
vector<ll>q[200100]; q[u].push_back(v); q[v].push_back(u);
枚举每个点,如果这个点相应的集合里的元素数量大于1,这个集合就对答案有贡献。
对于每个这样的集合,可以用一个for循环遍历所有元素,记录权值总和sum。
令sum=sum*sum,相当于分别把 每个点的权值 乘 所有点的权值总和 ,然后相加。sum=(w[1]+w[2]+...w[n])*(w[1]+w[2]+...w[n])。
这样会出现自己乘自己的情况,去掉。即减去w[1]*w[1]+w[2]*w[2],...+w[n]*w[n],可用一个变量记录这些的和。
题目还让求最大权值乘积,可以定义一个变量maxx遇到大的不断更新。如何更新?我是在 for循环遍历所有元素记录权值总和sum 的时候,定义两个变量b1,b2,表示集合中最大和次大的权值。
if(w[q[i][j]]>=b1){b2=b1;b1=w[q[i][j]];} //w表示权值,q表示第i个点的集合中第j个元素。 else if(w[q[i][j]]>=b2){b2=w[q[i][j]];}
for循环完成后
maxx=max(maxx,b2*b1);
当时写的时候也担心会不会超时,因为用了两个for循环,第一层遍历每个点 ,n ≤ 200,000,第二层遍历每个集合中的点。
会不会出现点很多 而且 每个集合中的点 也很多的情况。
后来想了想,耗时的部分在于遍历每个集合的所有元素。这是个树形结构,有n-1条边,一个点如果能成为 其他点的集合内的元素,需要一条边,边是无向的,一条边可以让两个点成为其他点的集合内的元素,有n-1条边,所以所有集合的元素数量之和不会超过2*(n-1),不会超时。
#include<bits/stdc++.h> #define ll long long #define scl(x) scanf("%lld",&x) #define sc(x) scanf("%ld",&x) using namespace std; ll w[200100]; const ll p=10007; vector<ll>q[200100]; int main() { int n; sc(n); ll u,v; for(int i=1;i<n;i++) { scl(u); scl(v); q[u].push_back(v); q[v].push_back(u); } for(int i=1;i<=n;i++) scl(w[i]); ll ans=0; ll maxx=-1; ll b1,b2; for(int i=1;i<=n;i++) if(q[i].size()>1) { b1=0;b2=0; ll ans1=0; ll ans2=0; for(int j=0;j<q[i].size();j++) { ans1+=w[q[i][j]]; ans1%=p; ans2+=w[q[i][j]]*w[q[i][j]]; ans2%=p; if(w[q[i][j]]>=b1){b2=b1;b1=w[q[i][j]];} else if(w[q[i][j]]>=b2){b2=w[q[i][j]];} } ans1*=ans1; ans1%=p; ans1-=ans2; if(ans1<0)ans1+=p; maxx=max(maxx,b2*b1); ans+=ans1; ans%=p; } printf("%lld %lld\n",maxx,ans); }
标签:超时 pac 自己 name space 树形结构 cto clu its
原文地址:https://www.cnblogs.com/tykws8/p/9939037.html