2021牛客暑期多校训练营6 J.Defend Your Country 点双连通分量
Posted kaka0010
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021牛客暑期多校训练营6 J.Defend Your Country 点双连通分量相关的知识,希望对你有一定的参考价值。
原题链接:https://ac.nowcoder.com/acm/contest/11257/J
题意
给定n个点,m条边的无向图,每个点都有 a i a_i ai的权值,定义重要程度为 − 1 联 通 块 大 小 ∑ a i -1^{联通块大小}\\sum ai −1联通块大小∑ai,你可以删除任意条边(可以为0),问最大重要程度是多少。
分析
分两种情况讨论一下
- 因为题目给定的图是连通图,那么如果n为偶数,直接输出答案。
- n为奇数的情况下,我们考虑删点,将联通块个数变为偶数。当然为了最优我们只删一个点肯定可以满足。那么讨论这个点怎么删。如果是割点,那么删去这个点之后会有很多个联通块,我们判断一下删完后剩余的联通块是不是都是偶数,如果有一个是奇数,那么不能删;如果不是割点,那么我们都可以删,因为不改变联通性质。最后对两种情况取min就好了。
Code
#include <bits/stdc++.h>
#define lowbit(i) i & -i
#define Debug(x) cout << x << endl
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<ll, ll> PII;
const ll INF = 1e18;
const int N = 1e6 + 10;
const int M = 1e6 + 10;
const int MOD = 1e9 + 7;
//-----------------------------------------------------------------IO Template
namespace StandardIO {
template<typename T>
inline void read(T &x) {
x = 0; T f = 1;
char c = getchar();
for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1;
for (; c >= '0' && c <= '9'; c = getchar()) x = x * 10 + c - '0';
x *= f;
}
template<typename T>
inline void write(T x) {
if (x < 0) putchar('-'), x *= -1;
if (x >= 10) write(x / 10);
putchar(x % 10 + '0');
}
}
using namespace StandardIO;
//-----------------------------------------------------------------IO Template
int dfn[N], low[N], idx, cut[N], stk[N], tp, ok[N], a[N], siz[N];
vector<int> g[N];
int n, m;
void tarjan(int u, int root) {
dfn[u] = low[u] = ++idx;
stk[++tp] = u;
siz[u] = 1;
int child = 0;
for (auto v : g[u]) {
if (!dfn[v]) {
tarjan(v, root);
siz[u] += siz[v];
low[u] = min(low[u], low[v]);
if (low[v] >= dfn[u]) {
child++;
if (child > 1 || u != root) cut[u] = 1;
if (siz[v] & 1) ok[u] = 0;
}
}
else
low[u] = min(low[u], dfn[v]);
}
}
inline void solve() {
int T; cin >> T; while (T--) {
cin >> n >> m;
ll ans = 0;
for (int i = 1; i <= n; i++) {
g[i].clear();
cut[i] = dfn[i] = low[i] = idx = tp = 0;
ok[i] = 1;
cin >> a[i];
ans += a[i];
}
for (int i = 1; i <= m; i++) {
int u, v; cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
if (n % 2 == 0) {
cout << ans << endl;
continue;
}
for (int i = 1; i <= n; i++) {
if (!dfn[i]) tarjan(i, i);
}
int mn = 1e9;
for (int i = 1; i <= n; i++) {
if (cut[i] && ok[i]) mn = min(mn, a[i]);
if (!cut[i]) mn = min(mn, a[i]);
}
cout << ans - 2 * mn << endl;
}
}
signed main() {
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
#ifdef ACM_LOCAL
freopen("input", "r", stdin);
freopen("output", "w", stdout);
signed test_index_for_debug = 1;
char acm_local_for_debug = 0;
do {
if (acm_local_for_debug == '$') exit(0);
if (test_index_for_debug > 20)
throw runtime_error("Check the stdin!!!");
auto start_clock_for_debug = clock();
solve();
auto end_clock_for_debug = clock();
cout << "Test " << test_index_for_debug << " successful" << endl;
cerr << "Test " << test_index_for_debug++ << " Run Time: "
<< double(end_clock_for_debug - start_clock_for_debug) / CLOCKS_PER_SEC << "s" << endl;
cout << "--------------------------------------------------" << endl;
} while (cin >> acm_local_for_debug && cin.putback(acm_local_for_debug));
#else
solve();
#endif
return 0;
}
以上是关于2021牛客暑期多校训练营6 J.Defend Your Country 点双连通分量的主要内容,如果未能解决你的问题,请参考以下文章