以前从来没写过求点双连通分量,现在写一下……
这题还用到了一个叫做block forest data structure,第一次见过……
——对于每一个点双联通分量S, 新建一个节点s, 向S中每个节点v连边. 这样一来, 新增的点和原来图中的点会构成一个森林
主要是这个性质很厉害:
【对于这个森林F, 删掉一个关键点或者一个叶子ii之后, 会得到一个新森林Fi, 这个Fi对应的连通块集合和Gi对应的连通块集合其实是一样的(不考虑那些新增的点)】
更具体的题解见http://www.cnblogs.com/WABoss/p/5696926.html
顺便学了一个扩大栈空间的方法:在编译器中加入命令--stack=16777216 (16777216相当于16MB空间)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 #include<stack> 7 typedef long long ll; 8 using namespace std; 9 const int mo=1000000007; 10 struct edge{int x,y;}; 11 vector<int> g[300010]; 12 stack<edge> st; 13 int dfn[300010],low[300010],f[100010],w[300010],s[300010],a[300010],root[300010],be[100010],fa[300010]; 14 bool cut[100010]; 15 int cas,n,m,t,h,x,y,sum; 16 17 ll quick(ll x) 18 { 19 int y=mo-2; ll s=1; 20 while (y) 21 { 22 if (y&1) s=s*x%mo; 23 x=x*x%mo; 24 y>>=1; 25 } 26 return s; 27 } 28 29 void dfs(int x) 30 { 31 dfn[x]=low[x]=++h; 32 int chi=0; 33 for (int i=0;i<g[x].size();i++) 34 { 35 int y=g[x][i]; 36 if (!dfn[y]) 37 { 38 st.push((edge){x,i}); 39 fa[y]=x;dfs(y); 40 chi++; 41 low[x]=min(low[x],low[y]); 42 if (low[y]>=dfn[x]) 43 { 44 cut[x]=1; 45 g[++t].clear(); 46 while (1) 47 { 48 int u=st.top().x,j=st.top().y; 49 int v=g[u][j]; st.pop(); 50 if (be[u]!=t) {g[t].push_back(u); be[u]=t;} 51 if (be[v]!=t) {g[t].push_back(v); be[v]=t;} 52 if (u==x&&j==i) break; 53 } 54 } 55 } 56 else if (dfn[y]<dfn[x]&&fa[x]!=y) 57 { 58 st.push((edge){x,i}); 59 low[x]=min(low[x],dfn[y]); 60 } 61 } 62 if (fa<0&&chi==1) cut[x]=0; 63 } 64 65 void dp(int x) 66 { 67 dfn[x]=root[h]; 68 if (x<=n) w[x]=a[x]; else w[x]=1; 69 s[x]=0; 70 for (int i=0; i<g[x].size(); i++) 71 { 72 int y=g[x][i]; 73 if (!dfn[y]) 74 { 75 dp(y); 76 w[x]=1ll*w[x]*w[y]%mo; 77 s[x]=(s[x]+w[y])%mo; 78 } 79 } 80 } 81 82 int main() 83 { 84 freopen("1006.in","r",stdin); 85 freopen("1006.ans","w",stdout); 86 scanf("%d",&cas); 87 while (cas--) 88 { 89 scanf("%d%d",&n,&m); 90 for (int i=1; i<=n; i++) 91 { 92 dfn[i]=fa[i]=cut[i]=be[i]=0; 93 scanf("%d",&a[i]); 94 } 95 for (int i=1; i<=m; i++) 96 { 97 scanf("%d%d",&x,&y); 98 g[x].push_back(y); 99 g[y].push_back(x); 100 } 101 t=n; 102 for (int i=1; i<=n; i++) 103 if (!dfn[i]) 104 { 105 h=0; 106 dfs(i); 107 } 108 for (int i=1; i<=n; i++) g[i].clear(); 109 for (int i=n+1; i<=t; i++) 110 for (int j=0; j<g[i].size(); j++) {int x=g[i][j]; g[x].push_back(i);} 111 for (int i=1; i<=t; i++) dfn[i]=f[i]=0; 112 h=sum=0; 113 for (int i=1; i<=t; i++) 114 if (!dfn[i]) 115 { 116 root[++h]=i; 117 dp(i); 118 sum=(sum+w[i])%mo; 119 } 120 for (int i=1; i<=n; i++) 121 { 122 if (dfn[i]==i) f[i]=0; else f[i]=1ll*w[dfn[i]]*quick(w[i])%mo; 123 f[i]=((ll)f[i]+sum-w[dfn[i]]+s[i]+mo)%mo; 124 } 125 int ans=0; 126 for (int i=1; i<=n; i++) ans=(ans+1ll*f[i]*i%mo)%mo; 127 printf("%d ",ans); 128 for (int i=1; i<=t; i++) g[i].clear(); 129 } 130 return 0; 131 }