P4331 [BalticOI 2004]Sequence 保序迴歸-左偏樹
阿新 • • 發佈:2020-10-07
目錄
內任意數字皆可。
那麼現在問題變成了依次遍歷序列,動態維護每一段區間中位數,保證每一段區間中位數單調不遞減即可。
如果\(a_i\)是單調不遞減的,那麼這就有\(n\)個區間,每個區間長度為\(1\),中位數是其本身。
如果發現某段區間中位數比前一段區間中位數小,就要合併這兩個區間。
合併區間可以用可並堆,例如左偏樹。
Problem
連結:
點我點我
題意:
n(1e6),a_i([0,2e9]),給定一個整數序列a1,...,an,求出一個遞增序列b1<b2<...<bn,使得a_i和b_i各
項之差絕對值和最小。\sum_{i=1}^{n}|a_i-b_i|.
思路:
左偏樹論文
首先令\(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('\n');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('\n');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 << '\n'; } 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\n", ans); rep(i, 1, n + 1) printf("%d%c", br[i], " \n"[i == n]); #ifdef LH_LOCAL cout << "time cost:" << 1.0 * clock() / CLOCKS_PER_SEC << "s" << endl; // system("pause"); #endif return 0; }