【bzoj2151】種樹
題面
題解
如果沒有相鄰限制的話,我們開一個大根堆每一次取最大的就行了,但是如果存在限制,我們就加入一個後悔操作,來做調整貪心。
首先如果我們選擇了一個點i,那麼其相鄰的點i−1,i+1,都不能選了,所以我們刪除這兩個點,因為i與它們兩個是互斥的。
所以我們加入後悔操作的時候,是用兩者之和減去a[i],即我們每選擇一個點,我們就加入一個新節點 node(i,a[i+1]+a[i−1]−a[i]),這樣就可以做到滿足限制條件下的調整了,另外就是維護位置,可以連結串列直接 O(1)做,或者set維護一下也可。
1、連結串列寫法
#include<iostream>
#include<queue>
using namespace std;
const int maxn = 200005;
struct node{
int id, val;
node(int id, int val):id(id),val(val){}
bool operator < (const node &b)const{return val<b.val;}
};
priority_queue<node>q;
int vis[maxn], pre[maxn], nxt[maxn];
void change(int x){
vis[x] = 1; //vis[i]==1,不在連結串列裡的點。
nxt[pre[x]] = nxt[x];
pre[nxt[x]] = pre[x];
pre[x] = 0; nxt[x] = 0;
}
int main(){
int n, m, a[maxn];
cin>>n>>m;
if(n<2*m){cout<<"Error!\n"; return 0;}
for(int i = 1; i <= n; i++){ cin>>a[i]; q.push(node(i,a[i])); }
for(int i = 2; i <= n; i++)pre[i] = i-1; pre[1]=n;
for(int i = 1; i < n; i++)nxt[i] = i+1; nxt[n]=1;
long long ans = 0;
for(int i = 1; i <= m; i++){
while(vis[q.top().id])q.pop();
node t = q.top(); q.pop();
ans += t.val;
int l = pre[t.id], r = nxt[t.id];
change(l); change(r);
a[t.id] = a[l]+a[r]-a[t.id];
q.push(node(t.id,a[t.id]));//反悔節點
}
cout<<ans<<'\n';
return 0;
}
2、STL寫法
#include<iostream>
#include<queue>
#include<set>
using namespace std;
const int maxn = 200005;
int n, m, a[maxn];
struct node{
int id, val;
node(int id, int val):id(id),val(val){}
bool operator < (const node &b)const{return val<b.val; }
};
struct data{
int id, val;
data(int id, int val):id(id),val(val){}
bool operator < (const data &b)const{return id<b.id; }
};
priority_queue<node>q;
set<data>s;
set<data>::iterator pre,nxt;
int main(){
cin>>n>>m;
if(n<2*m){cout<<"Error!\n";return 0;}
for(int i = 1; i <= n; i++){
cin>>a[i]; q.push(node(i,a[i]));
s.insert(data(i,a[i]));
}
long long ans = 0;
for(int i = 1; i <= m; i++){
node t = q.top(); q.pop();
while(!s.empty() && s.find(data(t.id,t.val))==s.end())
{ t = q.top(); q.pop();}
ans += t.val;
if(i == m)break;
data now = data(t.id,t.val);
nxt = s.upper_bound(now);
pre = s.lower_bound(now);
if(nxt == s.end())nxt = s.begin();
if(pre == s.begin())pre = --s.end();
else --pre;
data to = data(t.id,pre->val+nxt->val-t.val);
s.erase(s.find(now));
s.erase(pre);
s.erase(nxt);
s.insert(to);
q.push(node(to.id,to.val));
}
cout<<ans<<"\n";
return 0;
}
3、最後
垃圾樣例怎麼改都是對的。
相關文章
- bzoj2151: 種樹(貪心+堆)
- 梨樹種植,樹苗常發生的幾種蟲害DJSJS
- 「種樹專業戶」“樹”業有專攻
- [CSP-S 2023] 種樹
- AUTOCAD——沿著線種樹
- 洛谷-P1250 種樹
- 二叉樹的種類二叉樹
- python中樹有哪些種類Python
- 建樹的幾種常用方法
- 一種型別的樹貪心型別
- 樹狀陣列3種基本操作陣列
- 樹莓派四種登陸方法樹莓派
- 二叉樹四種遍歷二叉樹
- Python二叉樹的三種深度Python二叉樹
- [題解]P9755 [CSP-S 2023] 種樹
- 【自種樹自乘涼】Flutter 搭建開發環境Flutter開發環境
- 淺談三種求最小生成樹的方法
- Python——畫一棵漂亮的櫻花樹(不同種櫻花+玫瑰+聖誕樹喔)Python
- 樹莓派PICO刷入MicroPython核心的兩種方式樹莓派Python
- 小結:二叉樹的幾種實現方式二叉樹
- Python教程講解二叉樹的三種深度Python二叉樹
- 記一次有意思的種樹比賽
- 樹莓派使用入門:教孩子們用樹莓派學程式設計的 5 種方法樹莓派程式設計
- 二叉樹(BST)中序遍歷的三種方法二叉樹
- 值得了解的九種樹形資料結構 - Franco資料結構
- 表示式樹,一種提高程式碼複用性的方式
- 一文弄懂二叉樹的三種遍歷方式二叉樹
- Python實現二叉樹的三種深度遍歷方法!Python二叉樹
- 二叉樹的前序、中序、後序三種遍歷二叉樹
- 樹套樹
- 二叉樹的四種遍歷(遞迴與非遞迴)二叉樹遞迴
- BST(二叉搜尋樹)、AVL樹、紅黑樹、2-3樹、B樹、B+樹、LSM樹、Radix樹比較
- Trie樹,字典樹
- 樹:基本樹形
- 技能樹六大升級,讓學習成為一種習慣
- 多路查詢樹(2-3 樹、2-3-4 樹、B 樹、B+ 樹)
- 平衡二叉樹,B樹,B+樹二叉樹
- 二叉樹、B樹以及B+樹二叉樹