2020杭电多校第六场A Very Easy Graph Problem(并查集+dfs+bfs)【最小生成树】
题目
http://acm.hdu.edu.cn/showproblem.php?pid=6832
题意
给出一个无向连通图,里面的点分为0号点和1号点,第i条边的边权是2的i次。
询问所有1号点到0号点的最短路径之和。
题解
由于数据范围很大,所以肯定不能使用Floyd和dijkstra。
所以我们要通过它给的边,建立最小生成树,建立最小生成树这里用到的是并查集。(特别要注意!!!最后结果可能不止一个最小生成树!!!我在这里wa了好几个小时QAQ)
我们知道每一条边被计算的次数肯定是等于(左边0的个数 x 右边1的个数)+(左边1的个数 x 右边0的个数)
建立最小生成树之后,再用dfs遍历整个树,用son[u][0]和son[u][1]去记录,u节点有多少个1的子节点和多少个0子节点。用总数sum[0]和sum[1]再减去子节点0和1的个数,很简单就可以得到线段另一边0和1的个数了。
跑完bfs再用bfs去计算这个树的答案。
AC代码
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
#define PI acos(-1)
const int maxn = 1e6+5;
const ll mod = 1e9+7;
struct node
{
int e;
ll w;
friend bool operator < (node A, node B)
{
return A.w > B.w;
}
};
vector<node> g[maxn];
int pre[maxn],a[maxn],cnt[2],father[maxn][2],son[maxn][2];
int vis[maxn];
int n,m;
ll ans;
int find(int x)
{
if(pre[x]==x) return x;
else return pre[x] = find(pre[x]);
}
void dfs(int u)
{
cnt[a[u]]++;
father[u][0] = cnt[0];
father[u][1] = cnt[1];
int len = g[u].size();
vis[u]=1;
for(int i=0; i<len; i++)
{
int v = g[u][i].e;
if(vis[v]==0)
dfs(v);
}
son[u][0] = cnt[0]-father[u][0];
son[u][1] = cnt[1]-father[u][1];
}
void bfs(int x)
{
queue<int> q;
q.push(x);
vis[x] = 2;
while(!q.empty())
{
int u = q.front(),len = g[u].size();
q.pop();
for(int i=0; i<len; i++)
{
int v = g[u][i].e;
if(vis[v]==1)
{
vis[v]=2;
ll x1 = son[v][1]+a[v];
ll y0 = son[v][0]-a[v]+1;
ll y1 = cnt[1]-x1;
ll x0 = cnt[0]-y0;
// printf("u = %d,v = %d x1 = %d,x0 = %d y1 = %d,y0 = %d\n",u,v,x1,x0,y1,y0);
q.push(v);
ans = (ans+((x1*x0*g[u][i].w)%mod+(y1*y0*g[u][i].w)%mod)%mod)%mod;
}
}
}
}
int main()
{
// freopen("1.in","r",stdin);
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d %d",&n,&m);
for(int i=1; i<=n; i++)
{
g[i].clear();
vis[i]=0;
pre[i] = i;
scanf("%d",&a[i]);
}
ll w=1;
while(m--)
{
w = w*2%mod;
int u,v;
scanf("%d %d",&u,&v);
int fu = find(u),fv = find(v);
if(fu != fv)
{
node p;
p.e=v;
p.w=w;
g[u].push_back(p);
p.e=u;
g[v].push_back(p);
pre[fu] = fv;
}
}
ans = 0;
for(int i=1; i<=n; i++)
{
if(vis[i]==0)
{
// printf("dfs = %d\n",i);
cnt[0]=cnt[1]=0;
dfs(i);
bfs(i);
}
}
printf("%lld\n",ans);
}
return 0;
}
/*
2
5 4
0 0 1 1 0
1 2
1 3
2 4
2 5
4 2
1 0 1 0
1 2
2 3
*/