[关闭]
@ysner 2018-07-27T12:09:34.000000Z 字数 1316 阅读 1742

种树

贪心


题面

一个有个点的带点权环,最大化选取个不相邻的点得到的权值。

解析

显然可以贪心。
大根堆维护所有点权值。
每次堆顶点,同时把反悔,选相邻点的影响)塞入堆中,并标记相邻两点不可

有点卡壳的操作是把,即选在这个坑种树以后将它两边的坑合并为一个价值为(w[l]+w[r]-w[now])的坑,代替我们选择的坑。
这里非常的巧妙,就是如果选了这个坑就相当于不在那个中间的坑种树了,而是在它两边各种一棵。
可以用链表维护。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<algorithm>
  7. #include<queue>
  8. #define re register
  9. #define il inline
  10. #define ll long long
  11. #define max(a,b) ((a)>(b)?(a):(b))
  12. #define min(a,b) ((a)<(b)?(a):(b))
  13. #define fp(i,a,b) for(re int i=a;i<=b;i++)
  14. #define fq(i,a,b) for(re int i=a;i>=b;i--)
  15. using namespace std;
  16. const int N=5e5+100;
  17. struct dat{int w,id;bool operator < (const dat&o) const {return w<o.w;}};
  18. int n,m,a[N],L[N],R[N],vis[N];
  19. ll ans;
  20. priority_queue<dat>Q;
  21. il ll gi()
  22. {
  23. re ll x=0,t=1;
  24. re char ch=getchar();
  25. while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
  26. if(ch=='-') t=-1,ch=getchar();
  27. while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  28. return x*t;
  29. }
  30. il void Del(re int u){L[R[u]]=L[u];R[L[u]]=R[u];}
  31. int main()
  32. {
  33. n=gi();m=gi();
  34. if(n/2<m) {puts("Error!");return 0;}
  35. fp(i,1,n) a[i]=gi();
  36. fp(i,1,n) L[i]=i+1,R[i]=i-1;L[n]=1;R[1]=n;
  37. fp(i,1,n) Q.push((dat){a[i],i});
  38. while(m--)
  39. {
  40. while(vis[Q.top().id]) Q.pop();
  41. re dat u=Q.top();Q.pop();
  42. ans+=u.w;
  43. a[u.id]=a[L[u.id]]+a[R[u.id]]-u.w;
  44. Q.push((dat){a[u.id],u.id});
  45. vis[L[u.id]]=vis[R[u.id]]=1;
  46. Del(L[u.id]);Del(R[u.id]);
  47. }
  48. printf("%lld\n",ans);
  49. return 0;
  50. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注