P4331 [BalticOI 2004]Sequence 保序回归-左偏树

Problem

链接:
点我点我
题意:
n(1e6),a_i([0,2e9]),给定一个整数序列a1,...,an,求出一个递增序列b1<b2<...<bn,使得a_i和b_i各
项之差绝对值和最小。sum_{i=1}^{n}|a_i-b_i|.
思路:
左偏树论文
oi-wiki 左偏树
首先令(a_i-=i),将条件变为不递减序列。
如果(a_i)是单调不递增递减的,那么(b_i=a_i);如果(a_i)是单调不递增的,那么(b_i=中位数)
例如:求(|A-x|+|B-x|)的最小值,你一定知道答案是在([A,B])内任意数字皆可。
那么现在问题变成了依次遍历序列,动态维护每一段区间中位数,保证每一段区间中位数单调不递减即可。
如果(a_i)是单调不递减的,那么这就有(n)个区间,每个区间长度为(1),中位数是其本身。
如果发现某段区间中位数比前一段区间中位数小,就要合并这两个区间。
合并区间可以用可并堆,例如左偏树。

AC Code

/*
链接:
[点我点我](https://www.luogu.com.cn/problem/P4331)
题意:
n(1e6),a_i([0,2e9]),给定一个整数序列a1,...,an,求出一个递增序列b1<b2<...<bn,使得a_i和b_i各
项之差绝对值和最小。sum_{i=1}^{n}|a_i-b_i|.
思路:
保序回归论文题

*/
#pragma comment(linker, "/STACK:102400000,102400000")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize(3,"Ofast","inline")
#pragma GCC optimize("Ofast,no-stack-protector")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include <bits/stdc++.h>
#define fi first
#define se second
#define o2(x) (x) * (x)
#define mk make_pair
#define eb emplace_back
#define SZ(x) ((int)(x).size())
#define all(x) (x).begin(), (x).end()
#define clr(a, b) memset((a), (b), sizeof((a)))
#define rep(i,s,t) for(register int i=s;i<t;++i)
#define per(i,s,t) for(register int i=s;i>=t;--i)
#define GKD std::ios::sync_with_stdio(false);cin.tie(0)
#define my_unique(x) sort(all(x)), x.erase(unique(all(x)), x.end())
using namespace std;
typedef long long LL;
typedef long long int64;
typedef unsigned long long uint64;
typedef pair<int, int> pii;
// mt19937 rng(time(NULL));
// mt19937_64 rng64(chrono::steady_clock::now().time_since_epoch().count());
// mt19937_64 generator(std::clock());
// shuffle(arr, arr + n, generator);
inline int64 read() {
    int64 x = 0;int f = 0;char ch = getchar();
    while (ch < '0' || ch > '9') f |= (ch == '-'), ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch =
    getchar(); return x = f ? -x : x;
}
inline void write(int64 x, bool f = true) {
    if (x == 0) {putchar('0'); if(f)putchar('
');else putchar(' ');return;}
    if (x < 0) {putchar('-');x = -x;}
    static char s[23];
    int l = 0;
    while (x != 0)s[l++] = x % 10 + 48, x /= 10;
    while (l)putchar(s[--l]);
    if(f)putchar('
');else putchar(' ');
}
int lowbit(int x) { return x & (-x); }
template <class T>
T big(const T &a1, const T &a2) {return a1 > a2 ? a1 : a2;}
template <class T>
T sml(const T &a1, const T &a2) {return a1 < a2 ? a1 : a2;}
template <typename T, typename... R>
T big(const T &f, const R &... r) {return big(f, big(r...));}
template <typename T, typename... R>
T sml(const T &f, const R &... r) {return sml(f, sml(r...));}
void debug_out() { cout << '
'; }
template <typename T, typename... R>
void debug_out(const T &f, const R &... r) {
    cout << f << " ";
    debug_out(r...);
}
#ifdef LH_LOCAL
#define debug(...) cout << "[" << #__VA_ARGS__ << "]: ", debug_out(__VA_ARGS__);
#else
#define debug(...) ;
#endif
/*================Header Template==============*/
const int INF = 0x3f3f3f3f;
const int mod = 998244353;// 998244353
const int MXN = 1e6 + 5;
const int MXE = 2e6 + 5;
int n, m;
int br[MXN];
class Stack {
public:
    int l, r, rt, sz, val;
};
int top;
Stack stk[MXN];
class Node {
public:
    int l, r, d, val;
    int fa;
}tr[MXE];
void push_up(int x) {
    if(!x) return ;
    if(tr[x].d != tr[tr[x].r].d + 1) {
        tr[x].d = tr[tr[x].r].d + 1;
        push_up(tr[x].fa);
    }
}
int delx(int x, int y) {
    if(!x || !y) return x | y;
    if(tr[x].val < tr[y].val) swap(x, y);
    tr[x].r = delx(tr[x].r, y);
    tr[tr[x].r].fa = x;
    push_up(x);
    return x;
}
int merge(int x, int y) {
    if(!x || !y) return x | y;
    if(tr[x].val < tr[y].val) swap(x, y);
    tr[x].r = merge(tr[x].r, y);
    tr[tr[x].r].fa = x;
    if(tr[tr[x].l].d < tr[tr[x].r].d) swap(tr[x].l, tr[x].r);
    tr[x].d = tr[tr[x].r].d + 1;
    push_up(x);
    return x;
}

int main() {
#ifdef LH_LOCAL
    freopen("D:in.txt", "r", stdin);
    //freopen("D:out.txt", "w", stdout);
#endif
    n = read();
    rep(i, 1, n + 1) {
        tr[i].val = read() - i;
        if(i == 1) {
            stk[++top] = Stack{i, i, i, 1, tr[i].val};
            continue;
        }
        stk[++top] = Stack{i, i, i, 1, tr[i].val};
        while(top ^ 1 && stk[top - 1].val > stk[top].val) {
            -- top;
            stk[top].r = stk[top + 1].r;
            stk[top].rt = merge(stk[top].rt, stk[top + 1].rt);
            stk[top].sz += stk[top + 1].sz;
            while(stk[top].sz > (stk[top].r - stk[top].l + 1 + 1) / 2) {
                -- stk[top].sz;
                stk[top].rt = merge(tr[stk[top].rt].l, tr[stk[top].rt].r);
            }
            stk[top].val = tr[stk[top].rt].val;
        }
    }
    int64 ans = 0;
    int p = 1;
    rep(i, 1, n + 1) {
        while(p < top && i > stk[p].r) {
            ++ p;
        }
        ans += abs(tr[i].val - stk[p].val);
        br[i] = stk[p].val + i;
    }
    printf("%lld
", ans);
    rep(i, 1, n + 1) printf("%d%c", br[i], " 
"[i == n]);
#ifdef LH_LOCAL
    cout << "time cost:" << 1.0 * clock() / CLOCKS_PER_SEC << "s" << endl;
    // system("pause");
#endif
    return 0;
}

Probelm Description

原文地址:https://www.cnblogs.com/Cwolf9/p/13778798.html