[国家集训队] 种树

[国家集训队] 种树

一道好题。

题意

有一个 \(n\) 个点的环,第 \(i\) 个点的点权为 \(A_i\),求恰好包含 \(m\) 个点的最大独立集。

\(1 \leq m \leq n \leq 2 \times 10^5\)\(|A_i| \leq 10^3\)

思路

我们维护一个环形链表,然后进行反悔贪心。

具体地,每次选择点权最大的点,令其为 \(A_p\),则把 \(A_p\) 改为 \(A_{l_p}+A_{r_p}-A_p\) 并删去 \(l_p\)\(r_p\)

代码

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
long long a[200010];
int l[200010],r[200010];
bool vis[200010];
struct Node{
	int pos;
	long long num;
};
bool operator <(const Node &lhs,const Node &rhs){
	return lhs.num<rhs.num;
}
priority_queue<Node> pq;
int main(){
	int n,m;
	scanf("%d %d",&n,&m);
	if(m*2>n){
		printf("Error!");
		return 0;
	}
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
		pq.push((Node){i,a[i]});
		if(i>1) l[i]=i-1;
		else l[i]=n;
		if(i<n) r[i]=i+1;
		else r[i]=1;
	}
	long long ans=0;
	while(!pq.empty()){
		Node pre=pq.top();
		pq.pop();
		if(vis[pre.pos]){
			continue;
		}
		ans+=pre.num;
		int l_pre=l[pre.pos],r_pre=r[pre.pos];
		vis[l_pre]=vis[r_pre]=true;
		l[pre.pos]=l[l_pre];
		r[l[l_pre]]=pre.pos;
		r[pre.pos]=r[r_pre];
		l[r[r_pre]]=pre.pos;
		a[pre.pos]=a[l_pre]+a[r_pre]-a[pre.pos];
		pq.push((Node){pre.pos,a[pre.pos]});
		m--;
		if(m==0){
			break;
		}
	}
	printf("%lld",ans);
	return 0;
}
posted @ 2025-05-11 15:52  Oken喵~  阅读(1)  评论(0)    收藏  举报