传送门:点击打开链接
题意:有p个池塘,每个池塘有权值,有m条无向边将池塘连接,现在要除掉一些池塘,除掉的池塘必须要有一条边与其相连,无自环,求删除完池塘后,求连通分量中的池塘个数是偶数的联通分量所有权值之和
思路:类似拓扑排序,通过度数把点加入到队列中,然后开始删边和删点,点被删除后标记一下,然后就是把所有的点扫一遍DFS,统计连通分量中点的个数和权值而已了
#include<map>
#include<set>
#include<cmath>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define fuck printf("fuck")
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w+",stdout)
using namespace std;
typedef long long LL;
const int MX = 2e5 + 5;
int Head[MX], Next[MX], rear;
struct Edge {
int u, v;
} E[MX];
void edge_init() {
rear = 0;
memset(Head, -1, sizeof(Head));
}
void edge_add(int u, int v) {
E[rear].u = u;
E[rear].v = v;
Next[rear] = Head[u];
Head[u] = rear++;
}
int A[MX], IN[MX], vis[MX];
void DFS(int u, LL &sum, int &cnt) {
vis[u] = 1;
sum += A[u];
cnt++;
for(int i = Head[u]; ~i; i = Next[i]) {
int v = E[i].v;
if(vis[v] == 0) DFS(v, sum, cnt);
}
}
int main() {
int T, n, m; //FIN;
scanf("%d", &T);
while(T--) {
edge_init();
memset(vis, 0, sizeof(vis));
memset(IN, 0, sizeof(IN));
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) {
scanf("%d", &A[i]);
}
for(int i = 1; i <= m; i++) {
int u, v;
scanf("%d%d", &u, &v);
edge_add(u, v);
edge_add(v, u);
IN[u]++; IN[v]++;
}
queue<int>Q;
for(int i = 1; i <= n; i++) {
if(IN[i] <= 1) {
Q.push(i);
vis[i] = 1;
}
}
while(!Q.empty()) {
int u = Q.front();
Q.pop();
for(int i = Head[u]; ~i; i = Next[i]) {
int v = E[i].v;
IN[v]--;
if(IN[v] <= 1 && !vis[v]) {
vis[v] = 1;
Q.push(v);
}
}
}
LL ans = 0, tmp;
for(int i = 1; i <= n; i++) {
if(vis[i] == 0) {
tmp = 0;
int cnt = 0;
DFS(i, tmp, cnt);
if(cnt & 1) ans += tmp;
}
}
printf("%I64d\n", ans);
}
return 0;
}