hdu 5438 并查集
题目:hdu 5438
题意:
有一些池塘用管道连接着,但是主人没钱了,要清除一些与其他池塘相连数目少于2的池塘,包括一些独立的池塘。每个池塘都有一个价值,最后在删完一些池塘后求出有奇数个连通块的池塘的价值和。
分析:
记得是一道网络赛的题目。而且还记得我做的时候,用了deque,总是超时。又做了一下,好简单的题目。就是模拟一下删池塘的操作就好。先用并查集记录一下每个池塘所处的连通块,然后开始把不符合要求的池塘删去,最后把同一个连通块中并且度数大于1的池塘找出来,如果是奇数个,求一下和就好了。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<iostream>
using namespace std;
typedef long long ll;
const int N=10000+5;
int fa[N],in[N],val[N];
vector<int>g[N];
int findfa(int x){return x==fa[x]?x:fa[x]=findfa(fa[x]);}
int main()
{
int T; scanf("%d",&T);
int n,m;
while(~scanf("%d%d",&n,&m)){
for(int i=1;i<=n;i++)scanf("%d",&val[i]),g[i].clear(),fa[i]=i;
memset(in,0,sizeof(in));
int u,v;
for(int i=0;i<m;i++){
scanf("%d%d",&u,&v);
g[u].push_back(v); g[v].push_back(u);
in[u]++; in[v]++;
int x=findfa(u),y=findfa(v);
fa[x]=y;
}
while(1){
bool flag=0;
for(int i=1;i<=n;i++){
if(in[i]==1){
in[i]=0;
for(int j=0;j<g[i].size();j++)in[g[i][j]]--;
flag=1;
}
}
if(!flag)break;
}
ll ans=0;
vector<int>vec[n+1];
for(int i=1;i<=n;i++){
int x=findfa(i);
if(in[i]>1)vec[x].push_back(i);
}
for(int i=1;i<=n;i++){
if(vec[i].size()&1){
for(int j=0;j<vec[i].size();j++)ans+=val[vec[i][j]];
}
}
cout<<ans<<endl;
}
return 0;
}