洛谷 P1351 联合权值

传送门

思路

一道洛谷的绿题,虽然不是很难,但我还是做了很长时间

\(n\)个点,\(n-1\)条边,我们很容易就能想到这是一棵树,看数据范围,如果暴力枚举的话,只能拿部分分,这时候我们就回到题目中看,发现,只有距离为\(2\)才会产生价值的话,如果枚举一个节点,只有 它和它的孙子之间 或者 它的两个儿子之间 才会产生价值,所以我们就可以枚举这个节点,进行\(DFS\),期间进行更新就好了,具体的实现可以看代码

代码

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

inline int read() {
    char c = getchar();
    int x = 0, f = 1;
    for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
    for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
    return x * f;
}

const int N = 1e6 + 11;
const int M = 2e5 + 7;
const int mod = 10007;

//邻接表存图
struct node {
    int to, nxt;
} e[N];

int head[M], cnt = 0;

inline void add(int from, int to) {
    e[++cnt].to = to;
    e[cnt].nxt = head[from];
    head[from] = cnt;
}

int n, w[M], x, y, tot[M], ma[M], cma[M], ans, maxn;
//tot[x]数组记录x所有儿子的价值,ma[x]记录x所有儿子中的最大值,cma[x]记录x所有儿子中的次大值

//DFS!!
void dfs(int u, int fa) {
    //与孙子之间产生的价值
    for(int i = head[u]; i; i = e[i].nxt) { //枚举儿子节点
        int v = e[i].to;
        if(v == fa) continue;
        dfs(v, u);
        tot[u] = (tot[u] + w[v]) % mod; //tot[u]加上它儿子v的价值
        if(w[v] > ma[u]) ma[u] = w[v]; //找它所有儿子的最大值
        else cma[u] = max(cma[u], w[v]);
        maxn = max(maxn, w[u] * ma[v]);//答案中的最大值
        ans = (ans + 2 * w[u] * tot[v] % mod) % mod;//与孙子之间产生的价值(他到他孙子之间的距离一定是2),因为是双向的,所以要乘2
    }
    //儿子之间产生的价值
    for(int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].to;
        if(v == fa) continue;
        if(w[v] == ma[u]) maxn = max(maxn, w[v] * cma[u]); //如果是最大值就与次大值相乘
        else maxn = max(maxn, w[v] * ma[u]); //否则与最大值相乘
        ans = (ans + w[v] * (tot[u] - w[v]) % mod) % mod; //其中一个儿子与父节点所有儿子之间产生的价值就是w[v] * (tot[u] - w[v])
    }
}

int main() {
    n = read();
    for(int i = 1; i < n; i++) {
        x = read(), y = read();
        add(x, y);
        add(y, x);
    }
    for(int i = 1; i <= n; i++) w[i] = read();//cout << w[i] << '\n';
    dfs(1, 0);
    while(ans < 0) ans += mod; //答案可能是负的,只要是负的就一直加模数
    cout << maxn << " " << ans << '\n';
    return 0;
}

转载于:https://www.cnblogs.com/loceaner/p/11564488.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
大学生就业服务平台管理系统按照操作主体分为管理员和用户。管理员的功能包括学生档案管理、字典管理、试卷管理、试卷选题管理、试题表管理、考试记录表管理、答题详情表管理、错题表管理、法律法规管理、法律法规收藏管理、法律法规留言管理、就业分析管理、论坛管理、企业管理、简历管理、老师管理、简历投递管理、新闻资讯管理、新闻资讯收藏管理、新闻资讯留言管理、学生信息管理、宣传管理、学生管理、职位招聘管理、职位收藏管理、招聘咨询管理、管理员管理。用户的功能等。该系统采用了Mysql数据库,Java语言,Spring Boot框架等技术进行编程实现。 大学生就业服务平台管理系统可以提高大学生就业服务平台信息管理问题的解决效率,优化大学生就业服务平台信息处理流程,保证大学生就业服务平台信息数据的安全,它是一个非常可靠,非常安全的应用程序。 管理员权限操作的功能包括管理新闻信息,管理大学生就业服务平台信息,包括考试管理,培训管理,投递管理,薪资管理等,可以管理新闻信息。 考试管理界面,管理员在考试管理界面中可以对界面中显示,可以对考试信息的考试状态进行查看,可以添加新的考试信息等。投递管理界面,管理员在投递管理界面中查看投递种类信息,投递描述信息,新增投递信息等。新闻信息管理界面,管理员在新闻信息管理界面中新增新闻信息,可以删除新闻信息。新闻信息类型管理界面,管理员在新闻信息类型管理界面查看新闻信息的工作状态,可以对新闻信息的数据进行导出,可以添加新新闻信息的信息,可以编辑新闻信息信息,删除新闻信息信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值