HDU5739-Fantasia(tarjan求割点)
题意:给一个无向图n个点1~n,m条边,sigma(i*zi)%(1e9+7)。zi是这个图删掉i点之后的价值。一个图的价值是所有连通子图的价值之和,连通图的价值是每个点的乘积。
题解:讲道理这题不算难。注意一点就是一开始给的图不一定是连通的。然后就是割点会把一个连通图分成两个连通图,而其他点不影响图的连通性。至于割点直接tarjan就可以了。
而且dfs的过程中也可以处理出答案。这题只需要把每个连通子图求出而不需要处理出强连通分量,所以省去了tarjan算法中的stack数组。
变量比较多,写起来很烦。。
AC代码(1934MS):
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <vector>
#include <math.h>
using namespace std;
typedef long long ll;
const int N = ;
const ll mod = 1e9+;
int n, m; // 同题目描述
int a[N]; // 记录每个点的权值 struct Edge // 前向星存边
{
int to, next;
} edge[N*];
int cnt_edge;
int head[N];
void add_edge(int u, int v)
{
edge[cnt_edge].to = v;
edge[cnt_edge].next = head[u];
head[u] = cnt_edge++;
} int dfn[N], low[N], idx; // tarjan中用到的变量 ll mul; // 临时变量,记录每个图的所有点乘积
ll ans[N]; // 对于每个割点 如果分割了这个点 这棵树的答案
ll smul[N]; // 对于每个割点 分割它后所有分出来的子树的乘积
bool cut[N]; // 割点
int graph_cnt; // 连通图数量
vector<int> G[N]; // 记录每个连通图
ll graph[N]; // 每个连通图所有点的乘积
int kind[N]; // 每个点属于哪个连通图 void init(int n)
{
for (int i = ; i <= n; ++i) {
head[i] = -;
dfn[i] = ;
ans[i] = ;
smul[i] = ;
cut[i] = false;
G[i].clear();
}
cnt_edge = ;
idx = ;
graph_cnt = ;
} ll pow_mod(ll x, ll n)
{
ll ans = ;
while (n) {
if (n & ) ans = ans * x % mod;
x = x * x % mod;
n >>= ;
}
return ans;
} void tarjan(int u, int fa)
{
dfn[u] = low[u] = ++idx;
int child = ;
G[graph_cnt].push_back(u);
kind[u] = graph_cnt;
mul = mul * a[u] % mod;
for (int i = head[u]; i != -; i = edge[i].next) {
int v = edge[i].to;
if (v == fa) continue;
if (!dfn[v]) {
ll tmp = mul;
tarjan(v, u);
low[u] = min(low[u], low[v]);
if (low[v] >= dfn[u]) { // u是割点
++child;
ll inv = pow_mod(tmp, mod-);
tmp = mul * inv % mod; // mul/tmp 就是这个子图的乘积
ans[u] = (ans[u] + tmp) % mod;
smul[u] = smul[u] * tmp % mod;
}
} else {
low[u] = min(low[u], dfn[v]);
}
}
if ((fa == - && child > ) || (fa != - && child)) cut[u] = true; // u是割点
} int main(int argc, char const *argv[])
{
//freopen("in", "r", stdin);
int T;
cin >> T;
while (T--) {
scanf("%d%d", &n, &m);init(n);
for (int i = ; i <= n; ++i) scanf("%d", a+i);
int u, v;
while (m--) {
scanf("%d%d", &u, &v);
add_edge(u, v);
add_edge(v, u);
}
ll res = ;
for (int i = ; i <= n; ++i) {
if (!dfn[i]) {
mul = ;
tarjan(i, -);
graph[graph_cnt] = mul;
res = (res + mul) % mod;
for (unsigned j = ; j < G[graph_cnt].size(); ++j) {
u = G[graph_cnt][j];
if (u != i) {
ans[u] = (ans[u] + mul * pow_mod(smul[u]*a[u]%mod, mod - ) % mod) % mod; //mul/smul[j];
}
}
++graph_cnt;
}
}
ll rut = ;
for (int i = ; i <= n; ++i) {
ll tmp;
if (cut[i]) { // 如果是割点的话 就是这个点所在图分成多个子图
tmp = (res - graph[ kind[i] ] + ans[i] + mod) % mod;
} else {
if (G[kind[i]].size() == ) {
tmp = (res - a[i] + mod) % mod;
} else {
tmp = (res - graph[kind[i]] + graph[kind[i]] * pow_mod(a[i], mod-) % mod + mod) % mod;
}
}
rut = (rut + i * tmp % mod) % mod;
}
cout << rut << endl;
}
return ;
}
HDU5739-Fantasia(tarjan求割点)的更多相关文章
- UESTC 900 方老师炸弹 --Tarjan求割点及删点后连通分量数
Tarjan算法. 1.若u为根,且度大于1,则为割点 2.若u不为根,如果low[v]>=dfn[u],则u为割点(出现重边时可能导致等号,要判重边) 3.若low[v]>dfn[u], ...
- POJ 1144 Network(Tarjan求割点)
Network Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 12707 Accepted: 5835 Descript ...
- poj 1523 SPF(tarjan求割点)
本文出自 http://blog.csdn.net/shuangde800 ------------------------------------------------------------ ...
- poj_1144Network(tarjan求割点)
poj_1144Network(tarjan求割点) 标签: tarjan 割点割边模板 题目链接 Network Time Limit: 1000MS Memory Limit: 10000K To ...
- 洛谷P3388 【模板】割点(割顶)(tarjan求割点)
题目背景 割点 题目描述 给出一个n个点,m条边的无向图,求图的割点. 输入输出格式 输入格式: 第一行输入n,m 下面m行每行输入x,y表示x到y有一条边 输出格式: 第一行输出割点个数 第二行按照 ...
- [POJ1144][BZOJ2730]tarjan求割点
求割点 一种显然的n^2做法: 枚举每个点,去掉该点连出的边,然后判断整个图是否联通 用tarjan求割点: 分情况讨论 如果是root的话,其为割点当且仅当下方有两棵及以上的子树 其他情况 设当前节 ...
- poj1144 tarjan求割点
poj1144 tarjan求割点 额,算法没什么好说的,只是这道题的读入非常恶心. 注意,当前点x是否是割点,与low[x]无关,只和low[son]和dfn[x]有关. 还有,默代码的时候记住分目 ...
- tarjan求割点割边的思考
这个文章的思路是按照这里来的.这里讨论的都是无向图.应该有向图也差不多. 1.如何求割点 首先来看求割点.割点必须满足去掉其以后,图被分割.tarjan算法考虑了两个: 根节点如果有两颗及以上子树,它 ...
- Tarjan求割点和桥
by szTom 前置知识 邻接表存储及遍历图 tarjan求强连通分量 割点 割点的定义 在一个无向图中,如果有一个顶点集合,删除这个顶点集合以及这个集合中所有顶点相关联的边以后,图的连通分量增多, ...
- tarjan求割点与割边
tarjan求割点与割边 洛谷P3388 [模板]割点(割顶) 割点 解题思路: 求割点和割点数量模版,对于(u,v)如果low[v]>=dfn[u]那么u为割点,特判根结点,若根结点子树有超过 ...
随机推荐
- C/C++中几种经典的垃圾回收算法
1.引用计数算法 引用计数(Reference Counting)算法是每个对象计算指向它的指针的数量,当有一个指针指向自己时计数值加1:当删除一个指向自己的指针时,计数值减1,如果计数值减为0,说明 ...
- 咦,为DJANGO的ORM的QUERYSET增加数据列的样码,很好用哟
这个我真的没有查资料,是通过直觉和经验弄出来的,哈哈,感觉用深一点好. 这样在模板输出时,就更好控制啦.. if self.kwargs: if self.kwargs.has_key('search ...
- 【BZOJ 3190】 3190: [JLOI2013]赛车 (半平面交)
3190: [JLOI2013]赛车 Description 这里有一辆赛车比赛正在进行,赛场上一共有N辆车,分别称为个g1,g2--gn.赛道是一条无限长的直线.最初,gi位于距离起跑线前进ki的位 ...
- 苹果p12文件--一个苹果证书怎么多次使用(蛋疼,这些问题只有和其他企业合作才会遇到,别人的账号不可能给你,蛋疼....)
在苹果开发者网站申请的证书,是授权mac设备的开发或者发布的证书,这意味着一个设备对应一个证书,但是99美元账号只允许生成3个发布证书,两个开发证书,这满足不了多mac设备的使用,使用p12文件可以解 ...
- Hadoop常用命令汇总
启动Hadoop 进入HADOOP_HOME目录. 执行sh bin/start-all.sh 关闭Hadoop 进入HADOOP_HOME目录. 执行sh bin/stop-all.sh 1.查看指 ...
- 15个必知的Android开发者选项
Android开发者选项,看起来很简单的事情,其实很多同学对它了解得不够,Google用心良苦得为我们设计了这么多小开关都是有它的作用的,今天也花了点时间,过了一遍全部的30多个开关,从中整理出15个 ...
- 超实用的PHP代码片段
一.查看邮件是否已被阅读 当你在发送邮件时,你或许很想知道该邮件是否被对方已阅读.这里有段非常有趣的代码片段能够显示对方IP地址记录阅读的实际日期和时间. 1 2 3 4 5 6 7 8 9 10 1 ...
- MySQL数据库服务器安装标准
MySQL数据库服务器安装标准 (1).BIOS优化,阵列配置 1.1:关闭CPU节能,因为服务器品牌众多,BIOS设置不相同,主要是关闭CPU节能,如C1,DELLR730,已经智能设置,直接有个p ...
- Linux Shell常用命令手册(Updating)
检查远程端口是否对bash开放: nc -nvv $IP $PORT telnet $IP $PORT 当前任务的前后台切换: Ctrl + z fg 截取变量前5个字符: ${variable:0: ...
- Windows Embedded Compact 2013升级:VS2013也能编译
IT之家(www.ithome.com):Windows Embedded Compact 2013升级:VS2013也能编译 今天,微软为Windows Embedded Compact 2013送 ...