标签:超时 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