题意:
给你n个点m条边。
每次删除度为一的点和其对应的边,如果有新的度为一的点就继续前面的操作。
最后输出各个联通分量中个数为奇数的点权和
ACcode:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#define ll long long int
#define maxn 100005
using namespace std;
struct N{int to,next;}my[maxn];
int head[maxn],tot;
ll sum,num;
int de[maxn];
int vis[maxn];
bool ad[maxn];
ll ans[maxn];
inline void init(){memset(ad,0,sizeof(ad));memset(de,0,sizeof(de)); memset(vis,0,sizeof(vis));memset(head,-1,sizeof(head));tot=0;}
inline void add(int u,int v){
my[tot].to=v;my[tot].next=head[u];head[u]=tot++;
my[tot].to=u;my[tot].next=head[v];head[v]=tot++;
}
inline void bfs(int n){
queue<int>q;
for(int i=1;i<=n;++i)
if(vis[i]<2)q.push(i),ad[i]=1;
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=head[u];i!=-1;i=my[i].next){
int v=my[i].to;
vis[v]--;
vis[u]--;
if(vis[v]<2&&!ad[v])q.push(v),ad[v]=1;
}
}
}
inline void fun(int u){
for(int i=head[u];i!=-1;i=my[i].next){
int v=my[i].to;
if(!ad[u]&&vis[u]>=2){
num++;
sum+=ans[u];
ad[u]=1;
}
if(!ad[v]&&vis[v]>=2){
num++;
sum+=ans[v];
ad[v]=1;
fun(v);
}
}
}
int main(){
int loop,n,m;
scanf("%d",&loop);
while(loop--){
init();
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)scanf("%I64d",&ans[i]);
for(int i=1;i<=m;++i){
ll x,y;
scanf("%I64d%I64d",&x,&y);
vis[x]++;
vis[y]++;
add(x,y);
}
bfs(n);
ll aans=0;
for(int i=1;i<=n;++i){
if(vis[i]>=2&&!ad[i]){
num=sum=0;
fun(i);
if(num&1)
aans+=sum;
}
}
printf("%I64d\n",aans);
}
return 0;
}
/*
4
8 8
1 2 3 4 5 6 7 8
1 4
1 5
4 5
2 3
2 6
3 6
2 7
7 8
9 8
1 2 3 4 5 6 7 8 9
1 4
1 5
4 5
2 3
2 6
3 6
2 7
7 8
9 9
1 2 3 4 5 6 7 8 9
1 4
1 5
4 5
2 3
2 6
3 6
2 7
7 8
8 9
9 10
1 2 3 4 5 6 7 8 9
1 4
1 5
4 5
2 3
2 6
3 6
2 7
7 8
8 9
6 7
*/