题解:P16825 [AFOI 2025] B.岁月
题意:
给定一个
- 导出的子图
G_S 是森林(无环)。 - 删去
S 中的点后,剩余图仍连通。 -
思路
显然,最优解一定是之包含一个点。
假设最优解选取了点集
所以只要这个点不是割点显然比多个点情况下优秀,因为割点下剩余图不联通。
那就好做了,把割点求出来,遍历一下非割点中的找最小值即可,Tarjan 求割点的时间复杂度为
code
#include<bits/stdc++.h>
#define int long long
#ifdef _WIN32
#define getchar_unlocked _getchar_nolock
#define putchar_unlocked _putchar_nolock
#endif
#define endl '\n'
static char printff[20];
using namespace std;
const int N = 100005;
vector<int> edge[N];
int dfn[N],low[N],timer;
bool flagg[N];
int a[N];
int n,m;
int read(){
int k = 0,f = 1,c = getchar_unlocked();
for(;!isdigit(c);c = getchar_unlocked()){
if(c == '-')
f = -1;
}
for(;isdigit(c);c = getchar_unlocked())
k = k * 10 +(c ^ 48);
return k * f;
}
void print(int p){
unsigned int x = p;
if(p < 0){
putchar_unlocked('-');
x = -x;
}
if(x == 0){
putchar_unlocked('0');
return;
}
int len = 0;
while(x > 0){
printff[len++] = x % 10 + '0';
x /= 10;
}
while(len > 0){
putchar_unlocked(printff[--len]);
}
}
void fast(bool p){
if(p){
ios::sync_with_stdio(0);
cin.tie(nullptr);
return;
}else{
return;
}
}
void tarjan(int u,int fa){
dfn[u] = low[u] = ++timer;
int child = 0;
for(int v : edge[u]){
if(!dfn[v]){
child++;
tarjan(v,u);
low[u] = min(low[u],low[v]);
if(fa != 0 && low[v] >= dfn[u]){
flagg[u] = true;
}
} else if(v != fa){
low[u] = min(low[u],dfn[v]);
}
}
if(fa == 0 && child >= 2){
flagg[u] = true;
}
}
signed main(){
fast(0);
int T = read();
while(T--){
n = read();m = read();
timer = 0;
for(int i = 1;i <= n;i++){
edge[i].clear();
dfn[i] = low[i] = 0;
flagg[i] = false;
a[i] = read();
}
for(int i = 0;i < m;i++){
int u = read(),v = read();
edge[u].push_back(v);
edge[v].push_back(u);
}
if(n == 1){
print(a[1]);
putchar_unlocked('\n');
continue;
}
tarjan(1, 0);
int ans = LLONG_MAX;
for (int i = 1;i <= n;i++){
if (!flagg[i]){
ans = min(ans, a[i]);
}
}
print(ans);
putchar_unlocked('\n');
}
return 0;
}