n个点m条边,n<=1e6,初始的时候是连通的。第i个点权值是ai,现删掉一些边使得剩余连通分量的总权值最大。定义连通分量的权值,如果连通分量的包含奇数个点,则为-\sum ai,如果包含偶数个点,则为\sum ai. 首先初始n是偶数个点,则不用删边。 若n是奇数个点,则可以分成若干奇数个点+若干偶数个点。 我们发现奇数个点的连通块大小必然不超过1,原因在于假设3个点的连通块,分成2+1会更优。 因此n是奇数个点,目标是分成若干个孤立点+若干偶数个点。 再想想看,这些孤立点是什么。 第一种情况:可以变成一个非割点+(n-1)个点的偶图 第二种情况: 若非割点都很大怎么办,那么就要把割点作为孤立点。 割点作孤立点也只删除一个吗?反证:假如有>=3个割点作孤立点,那么能找到比它更优的(删1个),考虑4个正方形,割点连接相邻两个正方形。但是不是哪个割点都可以可以,得满足删除后连通块大小都为偶数。 这两种情况取个最小值。 寻找割点可以用tarjan算法来求解

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
const int N=1e6+2,M=2e6+2;

int n,m;
int a[N];
int h[N],e[M],ne[M],idx;
int dfn[N],low[N],timestamp;
int siz[N];
LL sum,ans; 

void add(int a,int b)
{
	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void tarjan(int u)
{
	siz[u]=1;
	bool flag=true;
	dfn[u]=low[u]=++timestamp;
	
	for(int i=h[u];~i;i=ne[i])
	{
		int j=e[i];
		if(!dfn[j])
		{
			tarjan(j);
			siz[u]+=siz[j];
			low[u]=min(low[u],low[j]);
			if(low[j]>=dfn[u]&&(siz[j]&1))flag=false;  
		}
		else low[u]=min(low[u],dfn[j]);
	}
	
	if(flag)ans=min(ans,(LL)a[u]);
}

int main()
{
	int T;
	scanf("%d", &T);
	while (T -- )
	{		
		timestamp=sum=idx=0;
		
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			h[i]=-1;
			dfn[i]=0;
			sum+=a[i];
		}
		for(int i=1;i<=m;i++)
		{
			int u,v;
			scanf("%d%d",&u,&v);
			add(u,v),add(v,u);
		}
		
		if(n%2==0) printf("%lld\n",sum);
		else
		{
			ans=sum; 
			tarjan(1);
			printf("%lld\n",sum-2*ans);	
		}
	}
	return 0;
}