题意:
逐次删除掉所有与一个点相邻的点,最后询问剩下的集合中权值和
思路:
拓扑排序去掉所有度为1的点,之后并查集合并
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <stack>
#include <vector>
#include <set>
using namespace std;
typedef long long ll;
vector<int> vec[100005];
set<int> sett[100005];
ll a[100005];
int fa[100005];
int num[100005];
ll val[100005];
int du[100005];
int find(int x)
{
if(fa[x]!=x)
{
fa[x]=find(fa[x]);
}
return fa[x];
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
vec[i].clear();
sett[i].clear();
fa[i]=i;
num[i]=0,val[i]=0;
}
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
num[i]=1,val[i]=a[i];
}
memset(du,0,sizeof(du));
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
vec[u].push_back(v);
vec[v].push_back(u);
if(sett[u].count(v)!=0)
continue;
sett[u].insert(v);
sett[v].insert(u);
du[u]++,du[v]++;
int rx,ry;
rx=find(u),ry=find(v);
if(rx!=ry)
{
fa[rx]=ry;
num[ry]+=num[rx];
val[ry]+=val[rx];
num[rx]=0,val[rx]=0;
}
}
stack<int> s;
for(int i=1;i<=n;i++)
{
if(du[i]==1)
{
s.push(i);
}
}
while(!s.empty())
{
int t=s.top();
int rt=find(t);
val[rt]-=a[t];
num[rt]--;
s.pop();
for(int i=0;i<vec[t].size();i++)
{
int v=vec[t][i];
du[v]--;
if(du[v]==1)
s.push(v);
}
}
ll ans=0;
for(int i=1;i<=n;i++)
{
if( (num[i]&1 ) &&(num[i]!=1))
{
ans+=val[i];
}
}
printf("%lld\n",ans);
}
}