Codeforces Round #474-E(树形dp)
一、题目链接
http://codeforces.com/contest/960/problem/B
二、题意
给定一棵$N$个节点的树,每个节点的权值$V$。定义树中两点$u_1$和$u_m$的权值和为$A(u_1, u_m) = V_{u_1} - V{u_2} + V{u_3} - V{u_4} + \cdots + (-1)^{m+1}V{u_m}$。求$\sum\limits_{u_i=1}^{N}\sum\limits_{u_j=1}^{N}A(u_i, u_j)\ \%\ (10^9+7)$。
三、思路
显然的树形$dp$。采用"两遍扫描"法。
设$dp1[i]$表示:从$i$出发,在以$i$为根的子树中,可得到的权值和。那么,很容易想到一个式子:预处理$dp1[i]=V[i]$,表示从$i$走到$i$自己的$A$值。然后,对于$i$的所有子节点$j$,有$dp1[i]\ +=\ V[i] - dp1[j]$。在思路中,为表述简洁,我们不考虑取模。如果这样,那就大错特错了。你会发现,连样例2都过不去。画一棵链式树可以发现,其实正确的式子是,$dp1[i] += f[j] * V[i] - dp1[j]$,其中$f[j]$表示以$j$为根节点的子树中节点的个数。为什么要乘以$f[j]$,因为对于以$j$为根的子树中每一个节点$r$,节点$i$都要走一遍去计算$A(i, r)$,所以这个地方要乘以一个$f[j]$。我一开始就是没写,导致一直样例都过不去。
设$dp2[i]$表示:从$i$出发,可得到的权值和(最后累加$dp2[i]$即可)。一遍扫描完成之后,显然有$dp2[1] = dp1[1]$(当然了,要看你的dfs是从哪个节点开始的)。然后,对于$i$的所有子节点$j$,有
\[dp2[j] = 除去以j为根的子树中所有节点的个数*V[j] + dp1[j] - (dp2[i] - 以j为根的子树中所有节点的个数*V[i] + dp1[j])\]
形式化(规范化)表示就是:
\[dp2[j] = (N - f[j]) * V[j] + dp1[j] - (dp2[i] - f[j] * V[i] + dp1[j])\]
即\[dp2[j] = (N - f[j]) * V[j] - (dp2[i] - f[j] * V[i])\]
注意这些"+"、“-”号的意义哦。在第一次扫描中减(实际上是+负的)了的,这里要加(实际上是-正的)回去,就等于没动(没+负也没-正)。同时,第一次加了$f[j] * V[i]$,那么,这一次要减去这个值。
另外,要注意的就是,取模的问题。因为涉及负数和乘法,一次加模数再取模不一定能保证结果为正。所以,要对$dp1[i]$和$dp2[i]$分别做两次取模。
四、代码实现
#include<bits/stdc++.h>
using namespace std;
#define pb(x) push_back(x)
#define mk(x, y) make_pair(x, y)
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
;
template <class T> inline void read(T &x) {
int t;
bool flag = false;
')) ;
';
+ t - ';
if(flag) x = -x;
}
typedef struct {
int to, next;
} Edge;
Edge tree[MAXN * ];
int head[MAXN], cnt;
void add(int from, int to) {
tree[cnt].to = to;
tree[cnt].next = head[from];
head[from] = cnt++;
}
void init() {
memset(head, -, sizeof(head));
cnt = ;
}
LL N, v[MAXN], dp0[MAXN], f0[MAXN], dp2[MAXN];
const LL MOD = 1000000007LL;
void dfs0(int root, int par) {
dp0[root] = v[root], f0[root] = ;
for(int i = head[root]; ~i; i = tree[i].next) {
int to = tree[i].to;
if(to != par) {
dfs0(to, root);
dp0[root] = (f0[to] * v[root] + dp0[root] - dp0[to] + MOD) % MOD;
dp0[root] = (dp0[root] + MOD) % MOD;
f0[root] += f0[to];
}
}
}
void dfs1(int root, int par) {
for(int i = head[root]; ~i; i = tree[i].next) {
int to = tree[i].to;
if(to != par) {
dp2[to] = ((N - f0[to]) * v[to] + dp0[to] - (dp2[root] + dp0[to] - f0[to] * v[root] + MOD) + MOD) % MOD;
dp2[to] = (dp2[to] + MOD) % MOD;
dfs1(to, root);
}
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("inputE.txt", "r", stdin);
#endif // ONLINE_JUDGE
init();
int a, b;
read(N);
; i <= N; ++i)read(v[i]);
; i < N; ++i) {
read(a), read(b);
add(a, b);
add(b, a);
}
dfs0(, -);
dp2[] = dp0[];
dfs1(, -);
LL ans = ;
; i <= N; ++i)ans = (ans + dp2[i]) % MOD;
cout << ans << endl;
;
}
Codeforces Round #474-E(树形dp)的更多相关文章
- Educational Codeforces Round 52F(树形DP,VECTOR)
#include<bits/stdc++.h>using namespace std;int n,k;vector<int>son[1000007];int dp[100000 ...
- codeforces 212E IT Restaurants(树形dp+背包思想)
题目链接:http://codeforces.com/problemset/problem/212/E 题目大意:给你一个无向树,现在用两种颜色去给这颗树上的节点染色.用(a,b)表示两种颜色分别染的 ...
- Codeforces 123E Maze(树形DP+期望)
[题目链接] http://codeforces.com/problemset/problem/123/E [题目大意] 给出一棵,给出从每个点出发的概率和以每个点为终点的概率,求出每次按照dfs序从 ...
- codeforces 709E E. Centroids(树形dp)
题目链接: E. Centroids time limit per test 4 seconds memory limit per test 512 megabytes input standard ...
- 2017 Wuhan University Programming Contest (Online Round) B Color 树形dp求染色方法数
/** 题目:Color 链接:https://oj.ejq.me/problem/23 题意:给定一颗树,将树上的点最多染成m种颜色,有些节点不可以染成某些颜色.相邻节点颜色不同.求染色方法数. 思 ...
- CodeForces 77C Beavermuncher-0xFF (树形dp)
不错的树形dp.一个结点能走多次,树形的最大特点是到达后继的路径是唯一的,那个如果一个结点无法往子结点走,那么子结点就不用考虑了. 有的结点不能走完它的子结点,而有的可能走完他的子节点以后还会剩下一些 ...
- bzoj 4424: Cf19E Fairy && codeforces 19E. Fairy【树形dp】
参考:https://blog.csdn.net/heheda_is_an_oier/article/details/51131641 这个找奇偶环的dp1真是巧妙,感觉像tarjan一样 首先分情况 ...
- Educational Codeforces Round 63-D(基础DP)
题目链接:https://codeforces.com/contest/1155/problem/D 题意:给定n个数,可以选择一段连续子段将其乘x,也可以不操作,求最大连续子段和. 思路:比赛时觉得 ...
- Educational Codeforces Round 62 E 局部dp + 定义状态取消后效性
https://codeforces.com/contest/1140/problem/E 局部dp + 定义状态取消后效性 题意 给你一个某些位置可以改变的字符串,假如字符串存在回文子串,那么这个字 ...
- Codeforces Round #544 (Div. 3) dp + 双指针
https://codeforces.com/contest/1133/problem/E 题意 给你n个数(n<=5000),你需要对其挑选并进行分组,总组数不能超过k(k<=5000) ...
随机推荐
- C++网络通信字节序问题
htonl(), ntohl(), htons(), ntohs() 函数 在C/C++写网络程序的时候,往往会遇到字节的网络顺序和主机顺序的问题.这是就可能用到htons(), ntohl(), n ...
- TCGA系列--GDCRNATools
https://github.com/Jialab-UCR/GDCRNATools GDCRNATools - An R package for downloading, organizing, an ...
- BZOJ 1269 【AHOI2006】 文本编辑器
题目链接:文本编辑器 这道题没啥好说的,直接上\(Splay\)就行了,板子题…… 但是我某个地方忘了下放标记导致调了一晚上 听说有个东西叫\(rope\)可以直接过?然而我并不会 保存一发板子: # ...
- SRM 585 DIV2
250pt: 一水... 500pt:题意: 给你一颗满二叉树的高度,然后找出出最少的不想交的路径并且该路径每个节点只经过一次. 思路:观察题目中给的图就会发现,其实每形成一个 就会存在一条路径. 我 ...
- 将数据提取到CSV文件中保存
这个方法可以实现,登录获取的token放入CSV文件,供后续调用,这里没有用登录举例 FileWriter fstream = new FileWriter("E:\\apache-jmet ...
- 使用Zend studio+WAMP来调试Wordpress后台的PHP程序的一些非常关键的信息(原创)
一.Zend studio代码格式化快捷键:选中代码,Ctrl+Shift+F( 注意,在英文输入发状态下使用!) .Zend studio实用快捷键 :http://www.zendstudio.n ...
- vscode的keybindings.json 和 AHK 脚本映射Win键
vscodehotkey.ahk https://github.com/m2nlight/AHKVSCodeLikeMac ; Shortcuts like mac ; Written by Bob ...
- 过滤器系列(二)—— Cuckoo filter
这一篇讲的是布谷过滤器(cuckoo fliter),这个名字来源于更早发表的布谷散列(cuckoo hash),尽管我也不知道为什么当初要给这种散列表起个鸟名=_= 由于布谷过滤器本身的思想就源自于 ...
- LocalStorage漏洞分析
之前LocalStorage爆出过一个漏洞,使用Chrome打开这个网站:http://filldisk.com,会将磁盘空间给撑爆,而且Chrome还会Crash.除了FireFox之外,其他浏览器 ...
- Shell 命令行,写一个自动整理 ~/Downloads/ 文件夹下文件的脚本
Shell 命令行,写一个自动整理 ~/Downloads/ 文件夹下文件的脚本 在 mac 或者 linux 系统中,我们的浏览器或者其他下载软件下载的文件全部都下载再 ~/Downloads/ 文 ...