专栏文章

[CF2063C] Remove Exactly Two 题解

CF2063C题解参与者 2已保存评论 1

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
1 条
当前快照
1 份
快照标识符
@miqf4k46
此快照首次捕获于
2025/12/04 03:46
3 个月前
此快照最后确认于
2025/12/04 03:46
3 个月前
查看原文

前言

CF 好题。

正文

题意:有一个无根树,移除 22 点之后联通分量的个数最大是多少。
以下皆钦定度数为入度和出度的和。
设节点 uu 的度数为 degu\text{deg}_u,我们对依次移除的 22i,ji,j 进行分类讨论。
  1. i,ji,j 不相邻:
    断开 ii 点,树显然会变成有 degi\text{deg}_i 个连通分量的图。
    断开 jj 点,会再多出 degj1\text{deg}_j-1 个联通分量。为什么呢?因为在刚刚断开的 degi\text{deg}_i 个分量里面必有 11 个包含 jj (也包含其他的节点),断开 jj 不会影响这一个连通分量,因此会少多出来 11 个连通分量。
    答案为 degi+degj1\text{deg}_i+\text{deg}_j-1
  2. i,ji,j 相邻:
    与 (1) 同样的逻辑,断开 ii 点,树还是会变成有 degi\text{deg}_i 个连通分量的图。
    但是,断开 jj 点,我们会比刚刚少多出来一个连通分量,因为移除 ii 点的同时 jj 点的度数也 1-1
    答案为 degi+degj2\text{deg}_i+\text{deg}_j-2
问题来了,那怎么实现呢?
具体的,我们枚举点 ii,然后根据上面的找出最大的满足条件的点 jj
注意到我们需要一个能实时排序,插入和移除的数据结构,我这里用的是 std::setstd::multiset
具体实现细节看代码。

Code

时间复杂度显然为 Θ(nlogn)\Theta(n \log n)
CPP
#include <bits/stdc++.h>
#ifdef LOCAL
	#include "debug.h"
#else
	#define debug(...) 42
#endif
#define mkp make_pair
#define pb emplace_back
#define endl "\n"
using namespace std;
using ll = long long;
int n,m,t,cnt=0;
const int maxn=2e5+10;
const double eps=1e-6;

int deg[maxn];
vector<int> e[maxn];
void solve(){
	int ans=0;
	cin>>n;
	fill(deg+1,deg+1+n,0);
	for(int i=1;i<=n;i++) e[i].clear();
	for(int i=1;i<=n-1;i++){
		int u,v;cin>>u>>v;
		deg[u]++,deg[v]++;
		e[u].pb(v);
		e[v].pb(u);
	}
	set<pair<int,int>> st;
	for(int i=1;i<=n;i++) st.insert(mkp(deg[i],i));
	for(int i=1;i<=n;i++){
		multiset<int> mt;
		st.erase(mkp(deg[i],i));
		for(int v:e[i]){mt.insert(deg[v]);st.erase(mkp(deg[v],v));}
		int case2=deg[i]+*prev(mt.end())-2;
		if(st.size()){
			int case1=deg[i]+(*prev(st.end())).first-1;
			ans=max({ans,case1,case2});
		}else{ans=max({ans,case2});}
		st.insert(mkp(deg[i],i));
		for(int v:e[i])	st.insert(mkp(deg[v],v));
	}
	cout<<ans<<endl;
}

signed main(){
	cin.tie(nullptr)->sync_with_stdio(0);
	cin>>t;
	while(t--) solve();
	return 0;
}

评论

1 条评论,欢迎与作者交流。

正在加载评论...