联合权值 noip2014 dfs

来源:互联网 发布:程序员可以兼职吗 编辑:程序博客网 时间:2024/05/17 21:54

Description


给定n点n-1条边的连通图和各点的权值,统计所有距离为2的两点权值乘积之和与最大乘积

Solution


题意让我想起了幂萎的敌敌

首先要想到题目给的是一棵树,那么就相当于对所有相邻节点的权积求和

dfs的过程中枚举节点求积是会T的,于是考虑O(n)的方法。
已知(a+b+c)2=a2+b2+c2+2ab+2ac+2bc
那么不难得到2(a+b+c)=(a+b+c)2a2+b2+c2
显然可以记录一下搞出来

洛谷a了但是学校题库不行(汗,拿着幂萎的标就交了

Code


#include <stdio.h>#include <vector>#define rep(i, st, ed) for (int i = st; i <= ed; i += 1)#define erg(i, now) for (int i = ls[now]; i; i = e[i].next)#define fill(x, t) memset(x, t, sizeof(x))#define ll long long#define pb push_back#define MOD 10007#define N 400001#define E N * 4 + 1#define L 30using namespace std;struct edge{int x, y, w, next;}e[E];ll w[N], tot = 0, mx = 0;int ls[N], d[N];inline void addEdge(int &cnt, int x, int y, int w = 1){    e[++ cnt] = (edge){x, y, w, ls[x]}; ls[x] = cnt;}inline ll max(ll x, ll y){    return x > y ? x: y;}inline void dfs1(int now, int dep){    d[now] = dep;    erg(i, now){        if (!d[e[i].y]){            dfs1(e[i].y, dep + 1);        }    }    vector<ll> v;    erg(i, now){        v.pb(e[i].y);    }    if (v.size()){        ll sum = 0, sqs = 0;        ll m1 = 0, m2;        rep(i, 0, v.size() - 1){            if (w[v[i]] > m1){                m2 = m1;                m1 = w[v[i]];            }else if (w[v[i]] > m2){                m2 = w[v[i]];            }            sum = (sum + w[v[i]]) % MOD;            sqs = (sqs + w[v[i]] * w[v[i]] % MOD) % MOD;        }        ll ret = (sum * sum % MOD + MOD - sqs) % MOD;        tot = (ret + tot) % MOD;        mx = max(mx, m1 * m2);    }}int main(void){    int n;    scanf("%d", &n);    int edgeCnt = 0;    rep(i, 1, n - 1){        int x, y;        scanf("%d%d", &x, &y);        addEdge(edgeCnt, x, y);        addEdge(edgeCnt, y, x);    }    rep(i, 1, n){        scanf("%lld", &w[i]);    }    dfs1(1, 1);    printf("%d %lld\n", mx, tot);    return 0;}
1 0