刚学拓扑排序,记录图用链式向前星
用vis和queue删 度为1的点
然后并查集或dfs算结果。。
拓扑很容易死循环+查代码查了好久。。。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
#include <cmath>
using namespace std;
#define FOR(i, l, r) for(int i = l; i <= r; i++)
#define REP(i, r, l) for(int i = r; i >= l; i--)
typedef long long ll;
double eps = 1e-6;
const int maxn = 10010;
const int mod = 1e9 + 7;
int f[maxn];
int u[maxn],v[maxn],w[maxn];
int head[maxn];
int ind[maxn];
int vis[maxn];
ll sum[maxn];
int num[maxn];
int tot;
int n,m;
struct edge
{
int from, to, next;
}edge[100010*2];
void addedge( int from, int to)
{
tot++;
edge[tot].from = from;
edge[tot].to = to;
edge[tot].next = head[from];
head[from] = tot;
}
int find(int x)
{
if(f[x] != x)
return f[x] = find(f[x]);
return x;
}
void unionset(int x,int y)
{
int xx = find(x),yy = find(y);
if(xx != yy)
{
f[yy] = xx;
num[xx] += num[yy];
sum[xx] += sum[yy];
}
}
void topsort()
{
queue <int> q;
FOR( i, 1, n)
if( ind[i] <= 1)
vis[i] = 1 , q.push(i);
while(!q.empty())
{
int temp=q.front();
q.pop();
for(int i = head[temp] ; i != -1 ; i = edge[i].next)
{
int x = edge[i].to;
if(vis[x]==0)
{
ind[x]--;
if( ind[x] == 1 )
{
vis[x]=1;
q.push(x);
}
}
}
}
}
int main()
{
int T;
scanf( "%d", &T);
while(T--){
scanf( "%d%d", &n, &m);
FOR(i,1,n)
scanf( "%d", &w[i]);
tot=0;
memset( head, -1, sizeof(head));
memset( ind, 0, sizeof(ind));
memset( vis, false, sizeof(vis));
FOR( i, 1, m)
{
scanf( "%d%d" , &u[i], &v[i]);
addedge( u[i], v[i]);
addedge( v[i], u[i]);
ind[u[i]]++ , ind[v[i]]++;
}
topsort();
FOR( i, 1, n)
f[i]=i, num[i]=1, sum[i]=w[i];
FOR( i, 1, m)
{
if(vis[u[i]] == 0 && vis[v[i]] == 0)
unionset(u[i], v[i]);
}
ll ans=0;
FOR( i, 1, n)
if( f[i] == i && vis[i]==0 && num[i]%2)
ans += sum[i];
printf("%I64d\n", ans);
}
return 0;
}