联合权值

来源:互联网 发布:程序员出差是去干什么 编辑:程序博客网 时间:2024/05/21 09:15

好。。。
一开始做的暴力只有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);}
1 1