联合权值

好。。。
一开始做的暴力只有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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值