码迷,mamicode.com
首页 > 其他好文 > 详细

2016多校 #2 1006 Fantasia

时间:2016-07-21 23:50:55      阅读:420      评论:0      收藏:0      [点我收藏+]

标签:

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 }
View Code

 

2016多校 #2 1006 Fantasia

标签:

原文地址:http://www.cnblogs.com/liuaohan/p/5693330.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!