题意:

给出一个无向图,每个顶点有一个权值\(w\),一个连通分量的权值为各个顶点的权值的乘积,一个图的权值为所有连通分量权值之和。

设删除顶点\(i\)后的图\(G_i\)的权值为\(z_i\),求\(\sum i \times z_i \; mod \; 10^9 + 7\)。

分析:

这里找到了一篇论文,借其中的图说明一下:

左图为原图,首先找出所有的点双连通分量(一种颜色对应一个双连通),然后重新建一个图(右图):

对每个双连通加一个点,然后对这个新点和双连通中所有的点连边(正方形对应原图中的点,圆形对应新加的点)。

这样就得到了一个森林(block forest),因为一个双连通建了一颗树,而不同双连通之间通过割点连通。

所以,原图中的割点都是非叶子节点,其他点都是叶子节点。

将每个新点的权值设为\(1\),这样就不影响原来连通分量的权值。

删除点\(u\)后,\(G_u\)的权值为\(\sum f(v_i)\),其中点\(v_i\)与点\(u\)相邻,\(f(v_i)\)为所在连通分量的权值。

对每棵树任选一个新点作为根,计算\(dp(u)\)为以\(u\)为根的子树的权值,然后再一遍\(DFS\)就可以\(O(n)\)计算删除每个点后的权值。

注意:只有一个点的树需要单独处理。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <stack>
#include <map>
using std::pair;
using std::vector;
using std::stack;
const int maxn = 200000 + 10;
const int MOD = 1000000007;
typedef pair<int, int> Edge;
typedef long long LL; LL mul(LL a, LL b) { return a * b % MOD; } void add(LL& a, LL b) { a += b; if(a >= MOD) a -= MOD; } LL sub(LL a, LL b) { b = MOD - b; a += b; if(a >= MOD) a -= MOD; return a; } LL pow_mod(LL a, int p) {
LL ans = 1;
while(p) {
if(p & 1) ans = mul(ans, a);
a = mul(a, a);
p >>= 1;
}
return ans;
} LL div(LL a, LL b) { return mul(a, pow_mod(b, MOD - 2)); } int n, m, cc_cnt; int w[maxn * 2];
bool vis[maxn * 2];
vector<int> G[maxn * 2], bcc[maxn], single; int dfs_clock, bcc_cnt;
int pre[maxn], bccno[maxn];
stack<Edge> S; int dfs(int u, int fa) {
int lowu = pre[u] = ++dfs_clock;
int child = 0;
for(int v : G[u]) {
Edge e(u, v);
if(!pre[v]) {
S.push(e);
child++;
int lowv = dfs(v, u);
lowu = std::min(lowu, lowv);
if(lowv >= pre[u]) {
bcc_cnt++; bcc[bcc_cnt].clear();
for(;;) {
Edge t = S.top(); S.pop();
int &x = t.first, &y = t.second;
if(bccno[x] != bcc_cnt) { bcc[bcc_cnt].push_back(x); bccno[x] = bcc_cnt; }
if(bccno[y] != bcc_cnt) { bcc[bcc_cnt].push_back(y); bccno[y] = bcc_cnt; }
if(x == u && y == v) break;
}
}
} else if(pre[v] < pre[u] && v != fa) {
S.push(e);
lowu = std::min(lowu, pre[v]);
}
}
if(fa < 0 && !child) single.push_back(u);
return lowu;
} void find_bcc() {
memset(pre, 0, sizeof(pre));
memset(bccno, 0, sizeof(bccno));
single.clear();
dfs_clock = bcc_cnt = 0;
for(int i = 0; i < n; i++) if(!pre[i]) {
dfs(i, -1);
cc_cnt++;
}
} void rebuild() {
for(int i = 0; i < n + bcc_cnt; i++) G[i].clear();
for(int i = 0; i < bcc_cnt; i++) {
int u = n + i; G[u].clear();
w[u] = 1;
for(int v : bcc[i + 1]) {
G[u].push_back(v);
G[v].push_back(u);
}
}
} vector<int> root;
LL d[maxn * 2]; void dp(int u) {
d[u] = w[u];
vis[u] = true;
for(int v : G[u]) if(!vis[v]) {
dp(v);
d[u] = mul(d[u], d[v]);
}
} LL ans[maxn], sum; void solve(int u, int fa, LL prod) {
ans[u] = 0;
for(int v : G[u]) if(v != fa) {
solve(v, u, prod);
if(u < n) add(ans[u], d[v]);
}
if(u < n) add(ans[u], div(prod, d[u]));
add(ans[u], sub(sum, prod));
} int main()
{
int T; scanf("%d", &T);
while(T--) {
scanf("%d%d", &n, &m);
for(int i = 0; i < n; i++) {
scanf("%d", w + i);
G[i].clear();
}
while(m--) {
int u, v; scanf("%d%d", &u, &v);
u--; v--;
G[u].push_back(v);
G[v].push_back(u);
}
find_bcc();
rebuild(); memset(vis, false, sizeof(vis));
root.clear();
sum = 0;
for(int u : single) add(sum, w[u]);
for(int i = 0; i < bcc_cnt; i++) {
int r = n + i; if(!vis[r]) {
root.push_back(r);
dp(r);
add(sum, d[r]);
}
} memset(ans, 0, sizeof(ans));
for(int r : root) solve(r, -1, d[r]); LL res = 0;
for(int u : single)
ans[u] = sub(sum, w[u]);
for(int i = 0; i < n; i++) add(res, mul(ans[i], i + 1));
printf("%lld\n", res);
} return 0;
}

HDU 5739 Fantasia 双连通分量 树形DP的更多相关文章

  1. HDU 2242 考研路茫茫——空调教室(边双连通分量+树形dp+重边标号)

    http://acm.hdu.edu.cn/showproblem.php?pid=2242 题意: 思路:首先求一下双连通分量,如果只有一个双连通分量,那么无论断哪根管子,图还是连通的. 最后只需要 ...

  2. hdu 4514 并查集+树形dp

    湫湫系列故事——设计风景线 Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Tot ...

  3. [HDU 5293]Tree chain problem(树形dp+树链剖分)

    [HDU 5293]Tree chain problem(树形dp+树链剖分) 题面 在一棵树中,给出若干条链和链的权值,求选取不相交的链使得权值和最大. 分析 考虑树形dp,dp[x]表示以x为子树 ...

  4. hdu 4612 Warm up 双连通+树形dp思想

    Warm up Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others) Total S ...

  5. HDU 2242 考研路茫茫—空调教室 (边双连通+树形DP)

    <题目链接> 题目大意: 给定一个连通图,每个点有点权,现在需要删除一条边,使得整张图分成两个连通块,问你删除这条边后,两联通块点权值和差值最小是多少. 解题分析: 删除一条边,使原连通图 ...

  6. HDU 5739 Fantasia

    可以将这个图转换成森林来进行树形dp求解.看了这篇具体教学才会的:http://www.cnblogs.com/WABoss/p/5696926.html 大致思路:求解一下点双连通分量(Tarjan ...

  7. HDU 5293 Tree chain problem 树形dp+dfs序+树状数组+LCA

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 题意: 给你一些链,每条链都有自己的价值,求不相交不重合的链能够组成的最大价值. 题解: 树形 ...

  8. hdu 4003 Find Metal Mineral 树形DP

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4003 Humans have discovered a kind of new metal miner ...

  9. HDU 5758 Explorer Bo(树形DP)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5758 [题目大意] 给出一棵树,每条路长度为1,允许从一个节点传送到任意一个节点,现在要求在传送次 ...

随机推荐

  1. 封装一个帮助类来写文件到android外置存储器上

    项目地址:点击打开 项目简介:写文件到android外置存储器的一个帮助类,和它的demo程序 它是如何工作的呢? 1.创建 AppExternalFileWriter 对象并传递context(上下 ...

  2. npm安装使用淘宝代理的方法(设置registry参数)

    公司防火墙问题导致 npm下载失败,安装使用cnpm不知道什么原因抽筋, 还有一个简单的办法,就是npm安装模块时,设置代理: npm install -g vue-cli --registry=ht ...

  3. POJ3233Matrix Power Series(矩阵快速幂)

    题意 题目链接 给出$n \times n$的矩阵$A$,求$\sum_{i = 1}^k A^i $,每个元素对$m$取模 Sol 考虑直接分治 当$k$为奇数时 $\sum_{i = 1}^k A ...

  4. Spring Boot相关组件的添加

    在勾选相关组件后, pom.xml文件上发生了根本的变化 1.这是最简单的项目的pom文件 <?xml version="1.0" encoding="UTF-8& ...

  5. 05、Win7上openSSH的安装与配置

    05.Win7上openSSH的安装与配置 1.概述 linux上的ssh命令在网络通信场景下非常方便.现在windows也支持ssh方式和远程主机进行访问.如果只是使用ssh简单的访问功能,就需要很 ...

  6. jQuery-添加新元素的方法(append()、prepend()、before()、after())

    1.以 HTML 创建新元素 var txt1="<p>Text.</p>"; 2.以 jQuery 创建新元素 var txt2=$("< ...

  7. libav(ffmpeg)简明教程(1)

    突然发现又有好久没有写技术blog了,主要原因是最近时间都用来研究libav去了(因为api极类似ffmpeg,虽然出自同一份代码的另外一个分支,因项目选用libav,故下文均用libav代替),其实 ...

  8. AOJ 558 Cheese(bfs)

    题意:网格图,老鼠吃奶酪,吃完奶酪体力值会增加,只能吃硬度不大于体力值的,问最小步数. 思路:按硬度从小到大的吃起,依次求最短路. 我用曼哈顿距离估价的A*,和普通bfs的time没区别啊,还把优先级 ...

  9. 一键备份脚本 backup.sh

    做网站最重要的是什么?数据!数据,是网站之本,备份,是每一个站长都应该重视的事情.但同时,备份也是一件繁琐和重复的事情.所以,这些事情,肯定能做到自动化的.下面来介绍一下这个一键备份脚本 backup ...

  10. 循环 -----JavaScript

    本文摘要:http://www.liaoxuefeng.com/ JavaScript的循环有两种,一种是for循环,通过初始条件.结束条件和递增条件来循环执行语句块: var x = 0; var ...