NOIP2014 联合权值 - 图论

30 篇文章 0 订阅

两个问题都需要按照每个节点的相邻点来思考解法。
把符合题目要求的,可产生联合权值的有序点对,称为联合点

  • 第一问
    每个节点的子节点(相邻点)之间,彼此组成联合点,具体看图。

    可以比较每个节点的相邻点的权值,得到最大子节点和次大子节点。
    他们的联合权值就是这个节点所能发现的最大联合权值。
    然后更新答案

ans=max(ans,max1max2) a n s = m a x ( a n s , m a x 1 ∗ m a x 2 )

  • 第二问
    直接两两相乘的话能得70分,剩下三个点会TLE
    但其实我们需要的只是乘积的和
    网上有加法分配律的算法,但我这里是难一点的…
    设一个点u的相邻点为a, b, c
    那么这个点能为答案贡献的值就是这三个点彼此的联合权值之和的两倍
    (联合权值是重复的,如(1,3)和(3,1)都要算上)
    我们要求的就是 2(ab+bc+ac) 2 ( a b + b c + a c )
    这个值可以转化为:
    (a+b+c)2=a2+b2+c2+2ab+2bc+2ac ( a + b + c ) 2 = a 2 + b 2 + c 2 + 2 a b + 2 b c + 2 a c

    2(ab+bc+ac)=(a+b+c)2(a2+b2+c2) 2 ( a b + b c + a c ) = ( a + b + c ) 2 − ( a 2 + b 2 + c 2 )

    ans=(i=1nison)2i=1n(ison)2 a n s = ( ∑ i = 1 n i s o n ) 2 − ∑ i = 1 n ( i s o n ) 2

    还要注意 如果不开long long 就要边加边模
#include <cstdio>
#include <algorithm>
const int maxn = 200010;
int tot=0,last[maxn],value[maxn];
bool vis[maxn];
int max1,max2,u,v,que,n,ans;
struct Edge{
    int u,v,to;
    Edge(){}
    Edge(int u, int v, int to) : u(u), v(v), to(to) {}
}e[maxn*2+10];
void addedge(int u,int v) {
    e[++tot] = Edge(u,v,last[u]);
    last[u] = tot;
}
int main() {
    scanf("%d",&n);
    for(int i=1; i<=n-1; i++){
        scanf("%d%d",&u,&v);
        addedge(u,v);
        addedge(v,u);
    }
    for(int i=1; i<=n; i++)
        scanf("%d",&value[i]);
    for(int u=1; u<=n; u++) {
        int s1=0,s2=0,max1=0,max2=0;
        for(int i=last[u]; i; i=e[i].to) {
            int v = e[i].v;
            if(value[v] > max1)
                max1 = value[v];
            else if(value[v] > max2)
                max2 = value[v];
            s1 = (s1%10007 + value[v]%10007) % 10007;
            s2 = (s2%10007 + value[v]*value[v]%10007) % 10007;    
        }
        ans = (ans%10007 + (s1*s1 - s2)%10007) % 10007;       
        que = std::max(que,max1*max2);      
    }
    printf("%d %d",que,ans%10007);
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值