就是给一个图,每个点有权值,边没有。然后会先依次删除度数<=1的点,一直删到不能删为止。然后求所有连通块中节点数为奇数的连通块的权值和的和。
首先删点就是拓扑序来删,然后求连通块可以DFS或者BFS或者并查集都可以。
训练时刚结束后,队友改了改,过的,直接邻接表(当然是vector存),拓扑序+BFS求连通块过掉的。
嗯,然后,去网上学了一发链式前向星,然后并查集搞连通块的,但我不清楚那些人用了链式前向星了,还要用两个数组来保存所有的边在并查集的时候用,链式前向星就可以遍历所有边啊,复杂度也是一样的。反正窝把存边的两个数组删掉后也A了。嗯,不管他们了。
代码:
#include <map>
#include <queue>
#include <stack>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define maxn 10003
#define maxm 100003
struct Edge
{
int next, to, w;
Edge() :next(0), to(0), w(0) { }
}edge[maxm];
int head[maxn], cnt = 0;
int val[maxn], degree[maxn];
bool vis[maxn];//记录该点是否被访问
int n, m;
int set[maxn];
int size[maxn];//结点数
long long sum[maxn];
void init_set()
{
for (int i = 1; i<maxn; ++i)
{
set[i] = i;
size[i] = 1;
sum[i] = val[i];
}
}
int findSet(int x)//路径压缩
{
if (x == set[x])
return x;
else
return set[x] = findSet(set[x]);
}
void unionSet(int x, int y)//启发式合并
{
int fx = findSet(x);
int fy = findSet(y);
if (fy == fx)
return;
if (size[fx] >= size[fy])
{
size[fx] += size[fy];
set[fy] = fx;
sum[fx] += sum[fy];
}
else
{
size[fy] += size[fx];
set[fx] = fy;
sum[fy] += sum[fx];
}
}
void add(int u, int v, int w = 1)
{
edge[cnt].w = w;
edge[cnt].to = v;
edge[cnt].next = head[u];
head[u] = cnt++;
}
void topo_del()
{
queue<int> que;
for (int i = 1; i <= n; ++i)
{
if (degree[i] <= 1)
{
degree[i] = 0;
vis[i] = false;
que.push(i);
}
}
while (!que.empty())
{
int x = que.front();
que.pop();
for (int i = head[x]; i != 0; i = edge[i].next)
{
int y = edge[i].to;
if (vis[y])
{
degree[y]--;
if (degree[y] == 1)
{
vis[y] = false;
que.push(y);
}
}
}
}
}
int main()
{
//freopen("input.txt", "r", stdin);
int T;
scanf("%d", &T);
while (T--)
{
long long ans = 0;
scanf("%d%d", &n, &m);
Edge etmp;
cnt = 1;
memset(vis, true, sizeof(bool)*maxn);
memset(degree, 0, sizeof(int)*maxn);
memset(head, 0, sizeof(int)*maxn);
memset(val, 0, sizeof(int)*maxn);
for (int i = 0; i < maxm; ++i)
edge[i] = etmp;
for (int i = 1; i <= n; ++i)
scanf("%d", &val[i]);
int a, b;
for (int i = 0; i < m; ++i)
{
scanf("%d%d", &a, &b);
add(a, b);
add(b, a);
degree[a]++;
degree[b]++;
}
topo_del();
init_set();
for (int i = 1; i <= n; ++i)
{
for (int j = head[i]; j != 0; j = edge[j].next)
if (vis[i] && vis[edge[j].to])
unionSet(i, edge[j].to);
}
for (int i = 1; i <= n; ++i)
if (vis[i] && set[i] == i&&size[i] & 1)
ans += sum[i];
printf("%I64d\n", ans);
}
//while (1);
//system("pause");
return 0;
}