题解 P3620 【[APIO/CTSC 2007]数据备份】

  • UPDATE

    LeTex好象又挂了

  • 题目链接:

    https://www.luogu.org/problemnew/show/P3620
    https://www.lydsy.com/JudgeOnline/problem.php?id=1150

  • 思路(来自《算法竞赛进阶指南》):

    容易知道,最优解中配对的楼肯定是相邻的,于是我们把所有相邻楼之间的距离\(D_1\),\(D_2\),\(D_3\)...\(D_n\)记录下来,放进一个堆里。

    很明显,每次都取堆中的最小值是不正确的。那么这就有个很妙的思路:假设\(D_i\)是最小值,那么我们就取出\(D_i\),同时取出\(D_{i-1}\)\(D_{i+1}\),然后再把一个一个值\(D_{i+1}\)+\(D_{i-1}\)-\(D_i\)的数放进堆,如果下一步这个新节点是最小值,很明显这是最优解。

    • 难点1:

    删了\(D_{i+1}\),\(D_{i-1}\)\(D_{i}\)后插入一个新节点,那它的前驱和后继怎么确定呢?最简单的方式当然就是用链表。

  • 难点2:

    我们要让堆和链表建立一个映射关系,怎么搞呢???我就在这里卡了好久,其实我们可以用反函数的思想。用一个数组v[]记录外面链表数组在堆中的下标,这样映射就建立了(其实这应该蛮好想的,我还是太弱了)

  • 代码:

/*By Rye_Catcher*/
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define ll long long 
using namespace std;
const int maxn=100005;
int a[maxn],pre[maxn],ne[maxn],v[maxn];
struct Small_Heap{
    int heap[maxn],n;
    inline void up(int s){
        int fa=s>>1;
        while(s>1){
            if(a[heap[s]]>1;
            }
            else break;
        }
    }
    inline void insert(int k){
        heap[++n]=k;
        v[k]=n;
        up(n);
    }
    inline void down(int fa){
        int s=fa<<1;
        while(s<=n){
            if(a[heap[s]]>a[heap[s+1]]&&sinline void read(T &x){
    x=0;int ne=0;char c;
    while(!isdigit(c=getchar()))ne=c=='-';
    x=c-48;
    while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;
    x=ne?-x:x;
    return ;
}
int main(){
    int la,x;
    ll ans=0;
    read(n),read(k);
    read(la);
    for(int i=2;i<=n;i++){
        read(x);
        a[i-1]=x-la;
        poi.insert(i-1);
        ne[i-1]=i,pre[i-1]=i-2;
        la=x;
    }
    for(register int i=1;i<=k;i++){  
        x=poi.heap[1];ans+=a[x];
        if(pre[x]==0)
        {
            poi.sub(x),poi.sub(ne[x]);
            pre[ne[ne[x]]]=0;
        }
        else if(ne[x]==n)
        {
            poi.sub(x),poi.sub(pre[x]);
            ne[pre[pre[x]]]=n;
        }
        else {      
        poi.sub(x);//poi.extract();   
        poi.sub(pre[x]),poi.sub(ne[x]);
        a[x]=a[pre[x]]+a[ne[x]]-a[x];
        poi.insert(x);
        pre[x]=pre[pre[x]],ne[pre[x]]=x;
        ne[x]=ne[ne[x]],pre[ne[x]]=x;
        }
    }
    cout<

转载于:https://www.cnblogs.com/Rye-Catcher/p/8834708.html

你可能感兴趣的:(题解 P3620 【[APIO/CTSC 2007]数据备份】)