洛谷P3620 [APIO/CTSC 2007]数据备份 学习笔记

反悔贪心,思维量非常大,重点如下:

1.d[i]存区间,表示i-i+1的长度。

2.二叉堆来维护最小值

3.每次只有两种可能,一种是取不相邻的边,另一种是取相邻的边,如果取相邻的边,那么必定是破坏之间的集合重组,在代码上显示的就是差值

4.合边操作并不是真的合边,而是差值刚好就能代表重组集合,在数学意义上相等,但是在物理意义上不等。

#include <iostream>
#include <set>
#include<queue>
using namespace std;
typedef long long LL;
typedef pair<LL, int> pll;
const int N = 100010;
int n, k;
int l[N], r[N];
LL d[N];
int vis[N];
void delete_node(int p){
    r[l[p]] = r[p];
    l[r[p]] = l[p];
}
priority_queue<pll,vector<pll>,greater<pll> > q;
int main(){
    cin >> n >> k;

    for (int i = 0; i < n; i ++ ) 
    cin >> d[i];
    for (int i = n - 1; i; i -- ) d[i] -= d[i - 1];

    d[0] = d[n] = 1e15;
    for (int i = 0; i <= n; i ++ ){
        l[i] = i - 1;
        r[i] = i + 1;
        q.push({d[i],i});
    }

    LL res = 0;
    while (k -- ){
        while(vis[q.top().second])
        q.pop();
        pll t=q.top();
        q.pop();
        int p = t.second, 
        left = l[p], right = r[p];
        vis[l[p]]=vis[r[p]]=1;
        delete_node(left), delete_node(right);
        res +=t.first;
        d[p] = d[left] + d[right] - d[p];
        q.push({d[p],p});
    }

    cout << res << endl;

    return 0;
}
View Code
原文地址:https://www.cnblogs.com/ctyakwf/p/12238631.html