HDU 5739 (点双连通 树DP)
来源:互联网 发布:淘宝宝贝流量突然下降 编辑:程序博客网 时间:2024/05/17 00:11
题目链接:点击这里
题意:定义连通分量的值是点权的积,图的值是所有联通分量值的和。求∑i∗(去掉i节点子图的值) 。
i不是割点容易求。如果是割点删掉就会形成很多新的联通分量,先把所有的点双连通分量求出来缩成一个新点,新点对联通分量里每个点都连边构造一个树,通过一次树dp求出每个点为根的子树的乘积以及每个点所有孩子子树的和。
trick:注意孤立点,新图的点数最多大概是原图的两倍。
#include <cstdio>#include <cstring>#include <algorithm>#include <iostream>#include <cmath>#include <map>#include <vector>#include <stack>using namespace std;#define maxn 400005#define maxm maxn*2#define mod 1000000007int n, m;int pre[maxn],dfs_clock,iscut[maxn],low[maxn],bcc_cnt,bccno[maxn]; vector<int>G[maxn],bcc[maxn]; struct Edge { int u,v; Edge(int from,int to) { u=from; v=to; } }; stack<Edge> S; int tarjan (int u,int fa) { int lowu=pre[u]=++dfs_clock; int child=0; int Max = G[u].size (); for(int i=0;i<Max;i++) { int v=G[u][i]; Edge e = Edge(u,v); if(!pre[v]) { S.push(e); child++; int lowv= tarjan (v,u); lowu=min(lowv,lowu); if(lowv>=pre[u]) { iscut[u]=true; bcc_cnt++;bcc[bcc_cnt].clear(); for(;;) { Edge x = S.top();S.pop(); if(bccno[x.u]!=bcc_cnt) { bcc[bcc_cnt].push_back(x.u); bccno[x.u]=bcc_cnt; } if(bccno[x.v]!=bcc_cnt) { bcc[bcc_cnt].push_back(x.v); bccno[x.v]=bcc_cnt; } if(x.u==u&&x.v==v) break; } } } else if(pre[v]<pre[u]&&v!=fa) { S.push(e); lowu=min(lowu,pre[v]); } } if(fa<0&&child==1) iscut[u]=0; return lowu; } void find_bcc () { memset (pre,0,sizeof(pre)); memset (iscut,0,sizeof(iscut)); memset (bccno,0,sizeof(bccno)); dfs_clock=bcc_cnt=0; for(int i=1; i <=n; i++) if(!pre[i]) tarjan(i,-1); } long long a[maxn];struct node { int v, next;}edge[maxm];int head[maxn], cnt;int degree[maxn];//用来判断孤立点int root[maxn];bool vis[maxn];long long sum[maxn], mul[maxn];void add_edge (int u, int v) { edge[cnt].v = v, edge[cnt].next = head[u], head[u] = cnt++;}void dfs (int u, int fa, int rt) { vis[u] = 1; root[u] = rt; sum[u] = 0; mul[u] = a[u]; for (int i = head[u]; i != - 1; i = edge[i].next) { int v = edge[i].v; if (v == fa) continue; dfs (v, u, rt); sum[u] = (sum[u] + mul[v]) % mod; mul[u] = mul[u] * mul[v] % mod; }}long long extend_gcd(long long a,long long b,long long &x,long long &y) { if(a==0&&b==0) return -1; if(b==0){x=1;y=0;return a;} long long d=extend_gcd(b,a%b,y,x); y-=a/b*x; return d; } long long mod_rev(long long a,long long n) { long long x,y; long long d=extend_gcd(a,n,x,y); if(d==1) return (x%n+n)%n; else return -1; } void solve () { memset (head, -1, sizeof head); cnt = 0; for (int i = 1; i <= bcc_cnt; i++) { int u = i+n, Max = bcc[i].size (); a[u] = 1; for (int j = 0; j < Max; j++) { int v = bcc[i][j]; add_edge (u, v); add_edge (v, u); } } memset (vis, 0, sizeof vis); long long tot = 0; for (int i = 1; i <= n+bcc_cnt; i++) { if (!vis[i]) { dfs (i, -1, i); tot = (tot+mul[i]) % mod; } } long long ans = 0; for (int i = 1; i <= n; i++) { long long tmp = 0, niyuan; if (!degree[i]) { tmp = ((tot-a[i])%mod + mod) % mod; } else if (!iscut[i]) { niyuan = mod_rev (a[i], mod); long long cur = mul[root[i]] * niyuan % mod; tmp = (tot - mul[root[i]] + cur); tmp = (tmp % mod + mod) % mod; } else { niyuan = mod_rev (mul[i], mod); long long cur; if (root[i] != i) { cur = mul[root[i]] * niyuan % mod; } else cur = 0; cur = (cur + sum[i]) % mod; tmp = (tot - mul[root[i]] + cur); tmp = (tmp % mod + mod) % mod; } ans = ans+1LL*i*tmp%mod; ans %= mod; } printf ("%lld\n", ans);}int main () { int t; scanf ("%d", &t); while (t--) { scanf ("%d%d", &n, &m); for (int i = 1; i <= n; i++) { scanf ("%lld", &a[i]); G[i].clear (); degree[i] = 0; } for (int i = 0; i < m; i++) { int u, v; scanf ("%d%d", &u, &v); degree[u]++, degree[v]++; G[u].push_back (v); G[v].push_back (u); } find_bcc (); solve (); } return 0;}/*106 61 1 1 1 1 11 22 33 11 42 53 6*/
0 0
- HDU 5739 (点双连通 树DP)
- hdu 5739(点双连通)
- HDU 5739(点双连通)
- HDU 5739 Fantasia(点双连通分量+树形DP)
- hdu 3749 点双连通
- hdu 3394(点双连通)
- 【HDU 5739】Fantasia(点双连通+dfs)
- HDU 2242 (Tarjan双连通缩点+树形DP)
- HDU 4005 The war 边-双连通缩点+树形dp
- HDU 5409 双连通缩点
- hdu 5739 点双连通分量+乘法逆元超详细讲解
- Hdu-5739 Fantasia (图论点双连通分量+DP)
- hdu 4612 Warm up(边-双连通+缩点+树的直径)
- hdu - 4338 - Simple Path - 割点 && 双连通
- HDU 4338 Simple Path 点双连通+lca
- HDU -- 3844 Mining Your Own Business(点双连通)
- HDU 4005 The war(边双连通+缩点)
- hdu 4612 Warm up 双连通缩点+树的直径
- POJ1001:高精度运算程序(X)
- 牛顿的三大定律
- display运用与理解
- LeetCode 299 Bulls and Cows
- Qt实现窗口关闭动画效果
- HDU 5739 (点双连通 树DP)
- HelloWorld
- opencv 3.0 for fc
- C语言排序算法
- java设计模式_单例模式
- 开发日记——手机安全卫士 Day04 2016-7-23 实现SIM换卡提醒功能
- 回溯法(Backtracking)
- 记一次自定义控件引起的内存优化:getCompoundDrawables();
- Scala的var,val