2016多校 #2 1006 Fantasia
http://acm.hdu.edu.cn/showproblem.php?pid=5739
已知一个无向图,每个结点有价值a[i]。一个连通图的价值定义为其所有结点价值之积;一个不连通图的价值为其所有连通分量的价值之和。
分别求删除每一个点后图的剩余部分的价值。n<=1e5,m<=2*1e5.
首先,原图可能有若干连通分量,这种情况很好处理。下面只对一个连通分量进行说明。
首先,删除一个点后图可能会分裂成若干部分,所以我们要对割点和非割点分别处理。
首先用tarjan求出所有割点,在此过程中即可顺便求出删除每个割点后,其所在原连通分量所分裂成的子图的价值。这需要我们对tarjan过程的dfs树有充分了解。对图中的某一个割点u,将u删除后图必定分割成大于一个的分支。在dfs树中,每一个分支要么对应u的一棵子树,要么是除去u这棵子树以外的部分。
我们用一个全局变量mul,在dfs过程中,每到一个结点就将mul乘此结点的价值,如果对结点u,发现其在dfs树中的子结点v,low[v]<=dfn[u],则以v为根的子树就是删除u后的一个分支。记对v进行dfs之前的mul为mem,则此分支的价值就是当前的mul/mem。将所有分支价值相加。
对于非dfs树根节点的割点u,其分支还包括除去dfs树中以u为根的子树的部分,用总的mul除以其子树那一部分之积即可。
这样查询就很简单了。
需要注意的是如果某连通分量只有一个结点,删除后此分量消失,若不特殊处理很容易将其价值按1计算。注意。
1 #include <iostream> 2 #include <cstdio> 3 #include <string> 4 #include <cstring> 5 #include <algorithm> 6 #include <cmath> 7 #include <vector> 8 using namespace std; 9 10 const int N = 100010,M = 200010,mod = 1e9+7; 11 int color,tot,p,n,m,start; 12 int dfn[N],low[N],spot[M*2],nex[M*2],head[N],c[N]; 13 long long all,mul,a[N],f[N],size[N],chmul[N]; 14 bool v[N],is[N]; 15 16 vector<int> have[N]; 17 18 void add(int x,int y) { 19 nex[++p] = head[x]; head[x] = p; spot[p] = y; 20 nex[++p] = head[y]; head[y] = p; spot[p] = x; 21 } 22 23 long long mypow(long long a,int b) 24 { 25 long long c = 1; 26 for(; b; b>>=1) { 27 if(b&1) c = c*a%mod; 28 a = a*a%mod; 29 } 30 return c; 31 } 32 33 long long ni(long long x) 34 { 35 return mypow(x, mod-2); 36 } 37 38 void tarjan(int x) 39 { 40 low[x] = dfn[x] = ++tot; 41 v[x] = 1; 42 c[x] = color; 43 have[color].push_back(x); 44 mul = mul*a[x]%mod; 45 long long mem; 46 int tp,y,cnt = 0; 47 for(tp = head[x]; tp; tp = nex[tp]) 48 { 49 y = spot[tp]; 50 if(!dfn[y]) 51 { 52 mem = mul; 53 tarjan(y); 54 low[x] = min(low[x], low[y]); 55 if(low[y]>=dfn[x]) { 56 cnt++; 57 long long temp = mul*ni(mem)%mod; 58 f[x] = (f[x]+temp)%mod; 59 (chmul[x] *= temp ) %= mod; 60 } 61 } 62 else if(v[y]) 63 low[x] = min(low[x], dfn[y]); 64 } 65 if(start==x && cnt>1 || start!=x && cnt) 66 is[x] = 1; 67 } 68 69 long long cal(int x) 70 { 71 long long temp,ret; 72 temp = (all-size[c[x]])%mod; 73 if(!is[x]) { 74 if(have[c[x]].size()==1) 75 ret = temp; 76 else 77 ret = (temp+size[c[x]]*ni(a[x]))%mod; 78 } 79 else ret = temp+f[x]; 80 return (ret%mod+mod)%mod; 81 } 82 83 int main() 84 { 85 int test,i,j,x,y; 86 for(cin >> test; test--; ) { 87 cin >> n >> m; 88 for(i = 1; i<=n; i++) 89 scanf("%I64d", &a[i]); 90 91 for(i = 1; i<=n; i++) 92 head[i] = 0; 93 p = 0; 94 95 for(i = 1; i<=m; i++) { 96 scanf("%d%d", &x,&y); 97 add(x,y); 98 } 99 100 for(i = 1; i<=n; i++) { 101 f[i] = 0, chmul[i] = 1; 102 is[i] = 0; 103 dfn[i] = low[i] = v[i] = c[i] = 0; 104 } 105 106 tot = all = color = 0; 107 for(i = 1; i<=n; i++) 108 have[i].clear(); 109 for(i = 1; i<=n; i++) 110 if(!dfn[i]) { 111 color++; 112 mul = 1; start = i; tarjan(i); 113 all = (all+mul)%mod; 114 size[color] = mul; 115 for(j = 0; j<have[color].size(); j++) 116 { 117 x = have[color][j]; 118 if(x!=start) { 119 (f[x] += mul*ni(chmul[x]*a[x]%mod)) %= mod; 120 } 121 } 122 } 123 long long ans = 0; 124 for(i = 1; i<=n; i++) { 125 ans = (ans+i*cal(i))%mod; 126 } 127 printf("%I64d\n", ans); 128 } 129 return 0; 130 }