[国家集训队] 种树
[国家集训队] 种树
一道好题。
题意
有一个 \(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;
}

浙公网安备 33010602011771号