zoukankan      html  css  js  c++  java
  • bzoj1150: [CTSC2007]数据备份Backup

    题目大意: 在n个点中,选出k对相邻的互不相同的点,使k段距离的总和最小。

    贪心,双向链表。

    首先,点之间的距离是动态的,所以要用堆来维护。

    每次都选择最近的点。但因为其他情况,可能最终不会选择这对点连在一起

    所以把俩个点旁边的路径的和减去俩个点之间距离再加进去,表示连旁边的俩条边,不连现在的边。

    要维护许多信息。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int maxn = 400000 + 10;
    const int INF = 0x3f3f3f3f;
    struct heap {
        int v,i;
    } h[maxn];
    int p[maxn],pre[maxn],next[maxn],pos[maxn];
    int n,m,ans=0,size=0;
    
    void pushup(int x) {
        while(h[x].v<h[x>>1].v) {
            pos[h[x>>1].i]=x;
            swap(h[x],h[x>>1]);
            x>>=1;
        }
        pos[h[x].i]=x;
    }
    
    void push(int v,int i) {
        h[++size].v=v;
        h[size].i=i;
        pos[i]=size;
        pushup(size);
    }
    
    void pushdown(int x) {
        int to;
        while(x <= size/2) {
            to=x<<1;
            if(to<size && h[to].v>h[to+1].v) to++;
            if(h[x].v > h[to].v) {
                pos[h[to].i]=x;
                swap(h[x],h[to]);    
                x=to;
            }
            else break;
        }
        pos[h[x].i]=x;
    }
    
    void del(int x) {
        h[x].v = INF;
        pushdown(x);
    }
    
    void init() {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%d",&p[i]);
        for(int i=2;i<=n;i++) {
            push(p[i]-p[i-1],i);
            pre[i]=i-1; next[i]=i+1;
        }
        pre[2]=next[n]=0;
    }
    
    void solve() {
        int a,b;
        heap k;
        while(m--) {
            k=h[1];
            if(pre[k.i]==-1) {
                ans+=k.v;
                del(1); del(pos[next[k.i]]);
                pre[next[next[k.i]]]=-1;
            }
            else if(next[k.i]==-1) {
                ans+=k.v;
                del(1); del(pos[pre[k.i]]);
                next[pre[pre[k.i]]]=-1;
            }
            else {
                ans+=k.v;
                a=next[k.i]; b=pre[k.i];
                pre[k.i]=pre[b];  next[pre[k.i]]=k.i;
                next[k.i]=next[a];  pre[next[k.i]]=k.i;
                h[1].v=h[pos[a]].v+h[pos[b]].v-h[1].v;
                del(pos[a]); del(pos[b]);
                pushdown(1);
            }
        }
        printf("%d
    ",ans);
    }
    
    int main() {
        init();
        solve();
        return 0;    
    }
  • 相关阅读:
    数据结构 链表笔记
    C语言 字符串操作 笔记
    数据结构 排序算法 笔记
    链表详解
    mysql常用命令
    图片压缩工具之grunt-contrib-imagemin
    正则表达式
    阿里云部署nodejs服务器(windows)
    canvas简介
    js面向对象
  • 原文地址:https://www.cnblogs.com/invoid/p/5535942.html
Copyright © 2011-2022 走看看