传送门

Description

无向连通图 \(G\) 有 \(n\) 个点, \(n-1\) 条边。点从 \(1\) 到 \(n\) 依次编号,编号为 \(i\) 的点的权值为 \(W_i\) ,每条边的长度均为 \(1\) 。图上两点 \((u, v)\) 的距离定义为 \(u\) 点到 \(v\) 点的最短距离。对于图 \(G\) 上的点对 \((u, v)\) ,若它们的距离为 \(2\) ,则它们之间会产生 \(W_v \times W_u\) 的联合权值。

Input

第一行包含 \(1\) 个整数 \(n\) 。

接下来 \(n-1\) 行,每行包含 \(2\) 个用空格隔开的正整数 \(u,v\) ,表示编号为 \(u\) 和编号为 \(v\) 的点之间有边相连。

最后 \(1\) 行,包含 \(n\) 个正整数,每两个正整数之间用一个空格隔开,其中第 \(i\) 个整数表示图 \(G\) 上编号为 \(i\) 的点的权值为 \(W_i\) 。

Output

输出共 \(1\) 行,包含 \(2\) 个整数,之间用一个空格隔开,依次为图 \(G\) 上联合权值的最大值和所有联合权值之和。由于所有联合权值之和可能很大,输出它时要对 \(10007\) 取余。

Sample Input

5
1 2
2 3
3 4
4 5
1 5 2 3 10

Sample Output

20 74

Hint

对于100%的数据, \(1 \leq n \leq 200000, 0 \leq W_i \leq 10000\) 。

Solution

比较显然的树形递推。

我们考虑对于一棵树,如果能知道根节点的所有以他的儿子为根的子树的答案,可以非常方便的得到以根节点为根的树的答案。这样状态就得以确定了。我们使用\(f(i)\)来代表以i为根的子树的答案。

对于转移,我们考虑根节点的答案首先是儿子的累加和,其次,根节点对孙子能够构成联合权值,这些都可以在枚举儿子的时候方便的计算出来。最后考虑任意儿子之间会产生联合权值。朴素做法当然是把儿子都存下来然后互相乘起来,这样的复杂度是\(O(n^2)\),会被菊花图卡吐血。

因为前面的儿子\(\times\)后面的儿子显然等于反过来乘,所以我们只需要前面的儿子\(\times\)后面的,最后把答案乘二即可。考虑对于根节点的第\(i\)个儿子,它对答案的贡献是【它的权值乘上它前面\(i-1\)儿子的权值的积】的和,根据乘法结合律,提取该节点的权值,它对答案的贡献就是它的权值乘上【前面儿子的的权值的和】的积这样我们可以直接维护他前面所有儿子的和,然后乘上该节点的权值,加入答案即可。

Code

#include<ctime>
#include<cstdio>
#include<cstdlib>
#define rg register
#define ci const int
#define cl const long long int typedef long long int ll; namespace IO {
char buf[50];
} template<typename T>
inline void qr(T &x) {
char ch=getchar(),lst=' ';
while(ch>'9'||ch<'0') lst=ch,ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if (lst=='-') x=-x;
} template<typename T>
inline void write(T x,const char aft,const bool pt) {
if(x<0) {putchar('-');x=-x;}
int top=0;
do {
IO::buf[++top]=x%10+'0';
x/=10;
} while(x);
while(top) putchar(IO::buf[top--]);
if(pt) putchar(aft);
} template <typename T>
inline T mmax(const T &a,const T &b) {if(a>b) return a;return b;}
template <typename T>
inline T mmin(const T &a,const T &b) {if(a<b) return a;return b;}
template <typename T>
inline T mabs(const T &a) {if(a<0) return -a;return a;} template <typename T>
inline void mswap(T &a,T &b) {T temp=a;a=b;b=temp;} const int maxn = 200010;
const int maxm = 400010;
const int MOD = 10007; struct Edge {
int to,nxt;
};
Edge edge[maxm];int hd[maxn],ecnt;
inline void cont(ci from,ci to) {
Edge &e=edge[++ecnt];
e.to=to;e.nxt=hd[from];hd[from]=ecnt;
} int a,b; int n,ans;
int MU[maxn];
int frog[maxn]; void dfs(ci,ci); int main() {
srand(time(NULL));
qr(n);
for(rg int i=1;i<n;++i) {
a=b=0;qr(a);qr(b);
cont(a,b);cont(b,a);
}
for(rg int i=1;i<=n;++i) qr(MU[i]);
int rt=rand()%n+1;
dfs(rt,0);
write(ans,' ',true);
write((frog[rt]<<1)%MOD,'\n',true);
} void dfs(ci k,ci fa) {
int _temp=0,_ans1=0,_ans2=0;
for(rg int i=hd[k];i;i=edge[i].nxt) {
int to=edge[i].to;
if(to==fa) continue;
frog[k]=(frog[k]+_temp*MU[to])%MOD;
_temp=(MU[to]+_temp)%MOD;
if(MU[to]>=_ans1) _ans2=_ans1,_ans1=MU[to];else if(MU[to]>_ans2) _ans2=MU[to];
ans=mmax(ans,_ans1*_ans2);
dfs(to,k);
frog[k]=(frog[k]+frog[to])%MOD;
for(rg int j=hd[to];j;j=edge[j].nxt) {
int &tt=edge[j].to;
if(tt==k) continue;
int _a=MU[tt]*MU[k];
frog[k]=(frog[k]+_a)%MOD;
ans=mmax(ans,_a);
}
}
}

Summary

当发现一个小部分因为复杂度超标而不可做的时候,不妨通过一些数学分析将复杂度降低从而获得正确的复杂度

【树形DP】【P1351】 【NOIP2014D1T2】联合权值的更多相关文章

  1. 洛谷 题解 P1351 【联合权值】

    Problem P1351 [联合权值] record 用时: 99ms 空间: 13068KB(12.76MB) 代码长度: 3.96KB 提交记录: R9883701 注: 使用了 o1 优化 o ...

  2. 【洛谷P1351】联合权值

    我们枚举中间点,当连的点数不小于2时进行处理 最大值好搞 求和:设中间点 i 所连所有点权之和为sum 则对于每个中间点i的联合权值之和为: w[j]*(sum-w[j])之和 #include< ...

  3. 【题解】洛谷P1351 [NOIP2014TG] 联合权值(树形结构+DFS)

    题目来源:洛谷P1351 思路 由题意可得图为一棵树 在一棵树上距离为2的两个点有两种情况 当前点与其爷爷 当前点的两个儿子 当情况为当前点与其爷爷时比较好操作 只需要在传递时不仅传递父亲 还传递爷爷 ...

  4. P1351 联合权值(树形dp)

    P1351 联合权值 想刷道水题还交了3次.....丢人 (1.没想到有两个点都是儿子的状况 2.到处乱%(大雾)) 先dfs一遍处理出父亲$fa[x]$ 蓝后再一遍dfs,搞搞就出来了. #incl ...

  5. NOIP2014提高组 联合权值(距离为2的树形dp)

    联合权值 题目描述 无向连通图 GG 有 nn 个点,n-1n−1 条边.点从 11 到 nn 依次编号,编号为 ii 的点的权值为 W_iWi​,每条边的长度均为 11.图上两点 (u, v)(u, ...

  6. Vijos1906 联合权值 NOIP2014Day1T2 树形动态规划

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - Vijos1906 题意概括 有一棵树,每一个节点都有一个权值w[i].下面说的x,y都是该树中的节点. 对于 ...

  7. P1351 联合权值[鬼畜解法]

    题目描述 无向连通图 G 有 n 个点,n−1 条边.点从 1 到 n 依次编号,编号为 i 的点的权值为 Wi​,每条边的长度均为 1.图上两点 (u,v) 的距离定义为 u 点到 v 点的最短距离 ...

  8. 联合权值dp

    联合权值 洛谷中可找到 题目传送门https://www.luogu.org/problemnew/show/P1351 这题我就得了70分(TLE)  GG了 就是遍历它孩子的孩子(爷爷和孙子),然 ...

  9. 洛谷 P1351 联合权值 题解

    P1351 联合权值 题目描述 无向连通图 \(G\) 有 \(n\) 个点,\(n-1\) 条边.点从 \(1\) 到 \(n\) 依次编号,编号为 \(i\) 的点的权值为 \(W_i\)​,每条 ...

随机推荐

  1. java后台接收微信服务号/订阅号消息

    1.申请订阅号(适合个人)或者服务号(适合企业) 微信公众平台 2.填写配置 服务器地址: 需要接收消息 的服务端接口地址 令牌:通话识别码,随便写,后端接收时,使用一样的就可以了. 消息加密秘钥 : ...

  2. JAVA基础学习之路(二)方法定义,重载,递归

    一,方法的定义: package test; public class test1 { public static void main(String args[]) { int result = ad ...

  3. hive使用spark引擎的几种情况

    使用spark引擎查询hive有以下几种方式:1>使用spark-sql(spark sql cli)2>使用spark-thrift提交查询sql3>使用hive on spark ...

  4. simhash和minhash实现理解

    文本相似度算法 minhash minhash 1. 把文档A分词形成分词向量L 2. 使用K个hash函数,然后每个hash将L里面的分词分别进行hash,然后得到K个被hash过的集合 3. 分别 ...

  5. Python的top-level脚本为什么在磁盘上没有对应的字节码?

    在Python中,如果你使用python script.py这样的方式运行Python脚本,那么script.py就被称为top-level脚本.对于Python来说,这个脚本的字节码是不会写入到磁盘 ...

  6. iOS- 网络访问JSON数据类型与XML数据类型的实现思路及它们之间的区别

    1.JSON (基本上移动开发的主要数据传输都是JSON) 1.1.JSON特点: a.[] 表示数组 b.{} 表示字典 - 对象模型建立关系 c.应用非常多,基本上移动开发的主要数据传输都是JSO ...

  7. iOS单利创建的方法

    我们在使用单例的时候有两种方法@synchronized,GCD,往往人们使用@synchronized,但是推荐使用GCD: 第一种(@synchronized): + (id)sharedInst ...

  8. iOS APP中第三方APP调用自己的APP,打开文件

    根据需求需要在项目中要打开word.pdf.excel等文件,在info.plist文件中添加 <key>CFBundleDocumentTypes</key> <arr ...

  9. TCP系列39—拥塞控制—2、拥塞相关算法及基础知识

    一.拥塞控制的相关算法 早期的TCP协议只有基于窗口的流控(flow control)机制而没有拥塞控制机制,因而易导致网络拥塞.1988年Jacobson针对TCP在网络拥塞控制方面的不足,提出了& ...

  10. JDK源码分析 – LinkedList

    LinkedList类的申明 public class LinkedList<E> extends AbstractSequentialList<E> implements L ...