好。。。
一开始做的暴力只有60分
code
#include<cstdio>
using namespace std;
int head[200001];
int len=0;
struct data{
int next,to;
}e[400001];
void connect(int x,int y)
{ e[++len].next=head[x];
e[len].to=y;
head[x]=len;
e[++len].next=head[y];
e[len].to=x;
head[y]=len;
}
long long ans=0,anss=0;
long long va[200001];
int p[200001];
int max(int x,int y)
{ if (x>y)
return x;
else
return y;
}
int ls[200001];
int dfs(int x)
{ p[x]=1;
int tmp=0;
int l=0;
for (int k=head[x];k;k=e[k].next)
{ int o=e[k].to;
if (p[o]==0)
{for (int i=1;i<=l;++i)
{ ans=(ans+ls[i]*va[o]*2)%10007;
anss=max(anss,ls[i]*va[o]);
}
ls[++l]=va[o];
}
}
int pd=0;
for (int i=head[x];i;i=e[i].next)
{ int v=e[i].to;
if (p[v])
continue;
for (int j=head[v];j;j=e[j].next)
{
int u=e[j].to;
if (x!=u)
{ ans=(ans+va[x]*va[u])%10007;
ans=(ans+va[x]*va[u])%10007;
anss=max(anss,va[x]*va[u]);
}
}
dfs(v);
}
}
void ycl(int x)
{ p[x]=1;
for (int i=head[x];i;i=e[i].next)
{ int v=e[i].to;
if (p[v])
e[i].next=e[e[i].next].next;
else
ycl(v);
}
}
int main()
{ int n;
scanf("%d",&n);
for (int i=1;i<=n-1;++i)
{ int x,y;
scanf("%d%d",&x,&y);
connect(x,y);
}
for (int i=1;i<=n;++i)
scanf("%d",&va[i]);
ycl(1);
dfs(1);
printf("%lld %lld",anss,ans);
}
还创造性的进行了砍边,结果还是tttt
想到了用把子节点和加起来的方式优化,但貌似求不了最大值(IQ低)
两个点之间要想产生联合权值,中间必须隔着一个点。我们可以以隔着的这个点为突破口。
问题一:最大值是多少?
我们枚举中间的那个点,在和这个点有连边的所有点中,找出权值最大的两个点即可。
问题二:计算联合权值的和?
还是枚举中间的那个点。比较笨的方法是两层枚举
假设和当前枚举的中间点有边相连的有a,b,c,d,e,……这些点,我们计算a*b+a*c+a*d+…+b*c+b*d+b*e+…+c*d+c*e+…
这样复杂度最坏可能到n^2级别。
怎样能够快速求出权值和?
令sum=a+b+c+…,我们只需要计算[a*(sum-a)+b*(sum-b)+…]/2即可。
code
#include<cstdio>
using namespace std;
int head[200001];
int len=0;
struct data{
int next,to;
}e[400001];
void connect(int x,int y)
{ e[++len].next=head[x];
e[len].to=y;
head[x]=len;
e[++len].next=head[y];
e[len].to=x;
head[y]=len;
}
long long ans=0,anss=0;
long long va[200001];
int max(int x,int y)
{ if (x>y)
return x;
else
return y;
}
int ls[200001];
int p[200001];
int dfs(int x)
{ p[x]=1;
int zd1=0,zd2=0;
int tmp=0;
for (int i=head[x];i;i=e[i].next)
{ int value=va[e[i].to];
tmp+=value;
if (value>zd1)
zd1=value;
else
if (value>zd2)
zd2=value;
}
anss=max(anss,zd1*zd2);
for (int i=head[x];i;i=e[i].next)
{ int v=e[i].to;
ans=(ans+tmp*va[v]-va[v]*va[v])%10007;
if (p[v]==0)
dfs(v);
}
}
int main()
{ int n;
scanf("%d",&n);
for (int i=1;i<=n-1;++i)
{ int x,y;
scanf("%d%d",&x,&y);
connect(x,y);
}
for (int i=1;i<=n;++i)
scanf("%d",&va[i]);
dfs(1);
printf("%lld %lld",anss,ans);
}
其实一开始的暴力如果想到怎么求最大值就过了QAQ
#include<cstdio>
using namespace std;
int head[200001];
int len=0;
struct data{
int next,to,last;
}e[400001];
void connect(int x,int y)
{ e[++len].next=head[x];
e[len].to=y;
head[x]=len;
e[++len].next=head[y];
e[len].to=x;
head[y]=len;
}
long long ans=0,anss=0;
long long va[200001];
int p[200001];
int max(int x,int y)
{ if (x>y)
return x;
else
return y;
}
int ls[200001];
int dfs(int x)
{ int tmp=0;
int l=0; int zd1=0,zd2=0;
for (int k=head[x];k;k=e[k].next)
{ int o=e[k].to;
tmp+=va[o];
if (va[o]>zd1)
zd1=va[o];
else
if (va[o]>zd2)
zd2=va[o];
}
anss=max(anss,zd2*zd1);
int pd=0;
for (int i=head[x];i;i=e[i].next)
{ int v=e[i].to;
for (int j=head[v];j;j=e[j].next)
{
int u=e[j].to;
if (x!=u)
{ ans=(ans+va[x]*va[u])%10007;
ans=(ans+va[x]*va[u])%10007;
anss=max(anss,va[x]*va[u]);
}
}
ans=(ans+va[v]*tmp-va[v]*va[v])%10007;
dfs(v);
}
}
void ycl(int x)
{ p[x]=1;
while (p[e[head[x]].to])
head[x]=e[head[x]].next;
int d=head[x];
for (int i=head[x];i;i=e[i].next)
{ int v=e[i].to;
if (p[v])
{ e[d].next=e[i].next;
d=e[e[i].next].next;
}
else
{ ycl(v);
d=i;
}
}
}
int main()
{ int n;
scanf("%d",&n);
for (int i=1;i<=n-1;++i)
{ int x,y;
scanf("%d%d",&x,&y);
connect(x,y);
}
for (int i=1;i<=n;++i)
scanf("%d",&va[i]);
ycl(1);
dfs(1);
printf("%lld %lld",anss,ans);
}