以前从来没写过求点双连通分量,现在写一下……

这题还用到了一个叫做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\n",ans);
128     for (int i=1; i<=t; i++) g[i].clear();
129   }
130   return 0;
131 }
View Code

 

posted on 2016-08-25 14:33  acphile  阅读(263)  评论(0编辑  收藏  举报