1. Islands War

题目链接:Islands War

n n n 个点形成一条链,给你 m m m 个点对,让你删掉若干条边使这些点对都不连通,问最少删多少条边。

可以直观的感受到,如果存在一组两两相交的区间,那么只需要删一条边,即最左边的右端点所在的边。

于是容易得到一个 O ( m log ⁡ m ) O(m\log m) O(mlogm) 的贪心做法,对所有区间按右端点排序即可。

#include <bits/stdc++.h>
using namespace std;
#define F first
#define S second
#define endl '\n'
using pii = pair<int, int>;
const int maxn = 1e5 + 5;
pii seg[maxn];
int main(){
	int n, m;
	cin >> n >> m;
	for(int i = 1; i <= m; ++i){
		cin >> seg[i].F >> seg[i].S;
	}
	sort(seg + 1, seg + m + 1, [](pii a, pii b){
		return a.S < b.S;
	});
	int now = 0, ans = 0;
	for(int i = 1; i <= m; ++i){
		if(now <= seg[i].F){
			now = seg[i].S;
			ans++;
		}
	}
	cout << ans << endl;
	return 0;
}

如果预处理一下每个点需要断的最近右端点,可以把复杂度优化到线性:

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
const int maxn = 1e5 + 5;
int a[maxn];
int main(){
	int n, m, L = maxn;
	cin >> n >> m;
	if(!m){
		cout << 0 << endl;
		return 0;
	}
	for(int i = 1, l, r; i <= m; ++i){
		cin >> l >> r;
		L = min(L, l);
		if(a[l] > r || !a[l]) a[l] = r;
	}
	int now = a[L], ans = 1;
	for(int i = 1; i <= n; ++i){
		if(!a[i]) continue;
		if(i >= now){
			ans++;
			now = a[i];
		} else if(now > a[i]){
			now = a[i];
		}
	}
	cout << ans << endl;
	return 0;
}

如果 n n n 个点形成一棵树,将删边改成删点,也可以用类似的方法来做,只需将点对的 LCA 按深度排序后从深的开始删即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值