Defend Your Country
题意:给你n个点m条边的无向图,每个点有权值a[i],对答案ans的贡献为a[i]*(-1)^所在连通块内点数,你可以删去任意的边,问你ans最大是多少
2≤n≤1e6
1≤m≤1e6
m≥n−1
结论:
若n为偶数,那么
a
n
s
=
∑
a
[
i
]
ans=\sum a[i]
ans=∑a[i]
若n为奇数,那么最多删除一个点
n为偶数很好写,n为奇数的时候,ans= ∑ a [ i ] − 2 ∗ a n s 1 \sum a[i] -2*ans1 ∑a[i]−2∗ans1,如果ans1这个点不是割点,那么就加入点集V中;如果是割点,那么我们删去这个点后判断一下多出的连通块里的个数是否为奇数,如果是奇数我们就不能删去这个点,否则就加入点集V中。最后ans1在V中找一个权值最小的即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
const int inf=0x3f3f3f3f;
vector<int>G[maxn];
void add(int x,int y)
{
G[x].push_back(y);G[y].push_back(x);
}
int dfn[maxn],low[maxn],k,siz[maxn];
int a[maxn],ans=inf,cut[maxn];
void tarjan(int u,int fa)
{
dfn[u]=low[u]=++k;
siz[u]=1;int son=0;
bool fl=false;
for(auto v:G[u])
{
if(fa==v) continue;
if(!dfn[v]) {
tarjan(v,u);son++;
low[u]=min(low[u],low[v]);
siz[u]+=siz[v];
if(u==fa) {
if(son>=2) {
cut[u]=1;
if(siz[v]&1) fl=true;
}
}
else {
if(dfn[u]<=low[v]) {
cut[u]=1;
if(siz[v]&1) fl=true;
}
}
}
else low[u]=min(low[u],dfn[v]);
}
if(!cut[u]||!fl) ans=min(ans,a[u]);
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int t;cin>>t;
while(t--)
{
int n,m;cin>>n>>m;
ll ans1=0;k=0;
for(int i=1;i<=n;i++)
dfn[i]=cut[i]=siz[i]=0;
for(int i=1;i<=n;i++)
cin>>a[i],G[i].clear(),ans1+=a[i];
while(m--)
{
int x,y;cin>>x>>y;
add(x,y);
}
if(n%2==0) {
cout<<ans1<<endl;
continue;
}
ans=inf;
tarjan(1,1);
cout<<ans1-2*ans<<endl;
}
return 0;
}