# Greedy# Set# Queue# Map

h028 - 202001_3 砍樹

🔗 前往 ZeroJudge 原題

題目描述

題目描述了在一個長條型林場中砍樹的問題。林場中有 N 棵樹,每棵樹都有座標和高度。砍樹的條件是:樹倒下時不會超出林場範圍,也不會壓到其他尚未砍除的樹木。目標是計算能砍除的樹木數量,以及這些樹木中的最高高度。

解題思路

本題採用貪心策略。首先,將所有樹的座標存入一個集合 s 中,並使用 map 儲存每個座標對應的高度。使用隊列 q 儲存樹的座標和高度。 每次從隊列中取出一個樹,判斷其左右倒下的範圍內是否有其他樹。如果沒有,則將該樹砍倒,並將其左右鄰居加入隊列。同時更新砍倒的樹木數量和最大高度。 使用集合 s 可以快速查詢指定範圍內是否存在其他樹。

複雜度分析

  • 時間複雜度: O(N log N)。主要時間花在集合的插入、刪除和查找操作上,這些操作的時間複雜度都是 O(log N)。隊列的操作和 map 的操作也都是 O(log N)。
  • 空間複雜度: O(N)。需要儲存所有樹的座標、高度以及隊列中的樹。

程式碼

#include <iostream>
#include <queue>
#include <set>
#include <map>
using namespace std;
long long n,l,ans,a[100005][2],amax;
map <long long,long long> mp;
queue <pair <long long,long long>> q;
set <long long> s;
int main(){
	cin.tie(0); ios::sync_with_stdio(false);
	cin >> n >> l;
	s.insert(0);
	mp[0]=mp[l]=1e10;
	s.insert(l);
	for(int i=0;i<n;++i){
		cin >> a[i][0];
		s.insert(a[i][0]);
	}
	for(int i=0;i<n;++i){
		cin >> a[i][1];
		mp[a[i][0]]=a[i][1];
		q.push(make_pair(a[i][0],a[i][1]));
	}
	while(q.empty()==0){
		pair <long long,long long> p=q.front();
		q.pop();
		if(s.count(p.first)==0)continue;
		long long lft=*(--s.find(p.first)),rgt=*(++s.find(p.first));
		//cout << lft << " " << rgt << "\n";
		if(lft<=p.first-p.second||rgt>=p.first+p.second){
			++ans;
			amax=max(amax,p.second);
			s.erase(p.first);
			q.push(make_pair(lft,mp[lft]));
			q.push(make_pair(rgt,mp[rgt]));
		}
	}
	cout << ans << "\n" << amax;
}

Discussion