您的位置:首页 > 其它

【HDU 5739】Fantasia(点双连通+dfs)

2016-07-25 13:36 453 查看
【HDU 5739】Fantasia(点双连通+dfs)

Fantasia

Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1240 Accepted Submission(s): 314

Problem Description

Professor Zhang has an undirected graph G with n vertices and m edges. Each vertex is attached with a weight wi. Let Gi be the graph after deleting the i-th vertex from graph G. Professor Zhang wants to find the weight of G1,G2,…,Gn.

The weight of a graph G is defined as follows:

If G is connected, then the weight of G is the product of the weight of each vertex in G.

Otherwise, the weight of G is the sum of the weight of all the connected components of G.

A connected component of an undirected graph G is a subgraph in which any two vertices are connected to each other by paths, and which is connected to no additional vertices in G.

Input

There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:

The first line contains two integers n and m (2≤n≤105,1≤m≤2×105) – the number of vertices and the number of edges.

The second line contains n integers w1,w2,…,wn (1≤wi≤109), denoting the weight of each vertex.

In the next m lines, each contains two integers xi and yi (1≤xi,yi≤n,xi≠yi), denoting an undirected edge.

There are at most 1000 test cases and ∑n,∑m≤1.5×106.

Output

For each test case, output an integer S=(∑i=1ni⋅zi)mod(109+7), where zi is the weight of Gi.

Sample Input

1

3 2

1 2 3

1 2

2 3

Sample Output

20

Author

zimpha

Source

2016 Multi-University Training Contest 2

题目大意:

给出一个无向图G(不保证图连通)和图中每个点的权值。

定义zi为从图G中删掉点i后的图Gi的重量。

定义图G的重量为:

如果G是连通图,则重量为图中各点权值的乘积

如果G不是连通图,则重量为所有最大连通图的重量的加和。

求 S=(∑i=1ni⋅zi)mod(109+7)

假设G初始为连通图,那么除了割点,其余点的zi为图中各点乘积(除了i点)

这样跑个Tarjan,对于同一个双连通图中的点,开一个新点,并把他们与新点连接一条边。做完后会变成一个新图(抛去旧边),或者说是一棵树。

叶子节点都是非割点,非叶子节点要么是新家的点,要么是割点。

这样搜一遍新建的树就能把S求出来了。因为图G初始未必是连通图

因此需要处理出来每个连通图的乘积。然后挨个图搜索,具体时间就不细述了,主要是Tarjan和建新图(树)那里。

代码如下:

#include <iostream>
#include <cmath>
#include <vector>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
#include <list>
#include <algorithm>
#include <map>
#include <set>
#define LL long long
#define Pr pair<int,int>
#define fread(ch) freopen(ch,"r",stdin)
#define fwrite(ch) freopen(ch,"w",stdout)

using namespace std;
const int INF = 0x3f3f3f3f;
const int msz = 10000;
const int mod = 1e9+7;
const double eps = 1e-8;

struct Edge
{
int v,next;
};

Edge eg[1666666];
int nd[233333];
int head[233333];
int val[233333];
bool vis[233333];
int dfn[233333],low[233333];
int tp,n,on,tim;
stack <int> s;

void Add(int u,int v,int *hd)
{
eg[tp].v = v;
eg[tp].next = hd[u];
hd[u] = tp++;
}

LL sum[233333];
LL all;
void init()
{
while(!s.empty()) s.pop();
memset(head,-1,sizeof(head));
memset(nd,-1,sizeof(head));
memset(vis,0,sizeof(vis));
tim = tp = 0;
int m;
scanf("%d%d",&n,&m);
//printf("%d %d\n",n,m);

for(int i = 1; i <= n; ++i)
scanf("%d",&val[i]);

int u,v;
while(m--)
{
scanf("%d%d",&u,&v);
Add(u,v,head);
Add(v,u,head);
}
}

void Pop(int u,int pre)
{
int v;

n++;
do
{
v = s.top();
s.pop();
//  printf("tp:%d\n",tp);
Add(v,n,nd);
Add(n,v,nd);
}while(v != u);

//  printf("tp:%d\n",tp);
Add(pre,n,nd);
Add(n,pre,nd);
val
= 1;
}

void Tarjan(int u,int root)
{
sum[root] = (sum[root]*val[u])%mod;
vis[u] = 1;
s.push(u);
dfn[u] = low[u] = tim++;

int v;
for(int i = head[u]; i != -1; i = eg[i].next)
{
v = eg[i].v;
if(!vis[v])
{
Tarjan(v,root);
low[u] = min(low[u],low[v]);

if(low[v] >= dfn[u])
{
Pop(v,u);
}
}
else low[u] = min(low[u],dfn[v]);
}
}

LL pow_m(LL a,int b)
{
LL ans = 1;
while(b)
{
if(b&1) ans = (ans*a)%mod;
b >>= 1;
a = (a*a)%mod;
}
return ans;
}

LL ans;
LL mul[233333];

void dfs(int u,int root,LL oth)
{
//printf("inu:%d\n",u);
mul[u] = val[u];
vis[u] = 1;
int v;
LL cnt = 0;
for(int i = nd[u]; i != -1; i = eg[i].next)
{
//printf("u:%d pre:%d\n",u,pre);
v = eg[i].v;
//printf("%d:%d-%d\n",i,u,v);
if(vis[v]) continue;
dfs(v,root,oth);
mul[u] = (mul[u]*mul[v])%mod;
if(u <= on) cnt = (cnt+mul[v])%mod;
}
//printf("outu:%d\n",u);

if(u <= on)
{
if(u == root) ans = (ans+((u*((cnt+oth)%mod))%mod))%mod;
else ans = (ans+((u*((cnt+((sum[root]*pow_m(mul[u],mod-2))%mod)+oth)%mod))%mod))%mod;
//printf("sum:%lld cnt:%lld mul:%lld\n",sum,cnt,mul[u]);
//printf("%d*%lld\n",u,((((cnt+((sum*pow_m(mul[u],mod-2))%mod))%mod))%mod));
}
//printf("%d=%lld\n",u,cnt);
}

int main()
{
//  fread("data1.in");
//  fwrite("test.out");

int t;

scanf("%d",&t);

while(t--)
{
//printf("%d\n",t);
init();
on = n;
all = 0;
for(int i = 1; i <= on; ++i)
{
if(vis[i]) continue;
sum[i] = 1;
Tarjan(i,i);
all = (all+sum[i])%mod;
}
//printf("%d %d\n",n,tp);

memset(vis,0,sizeof(vis));
ans = 0;
for(int i = 1; i <= n; ++i)
{
if(vis[i]) continue;
dfs(i,i,(((all-sum[i])%mod)+mod)%mod);
}
printf("%lld\n",ans);
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: