1. 程式人生 > >Luogu 3466 [POI2008]KLO-Building blocks

Luogu 3466 [POI2008]KLO-Building blocks

std printf string 一個數 none algo 最小 view eve

BZOJ 1112。

題意相當於在一個長度為$k$的區間內選擇一個數$s$使$\sum_{i = 1}^{k}\left | a_i - s \right |$最小。

很顯然是中位數。

然後只要寫一個能查詢長度為$k$的區間的中位數,以及小於和大於這個中位數的總和和個數的數據結構即可。

線段樹平衡樹對頂堆隨便維護。

我選擇權值線段樹。

時間復雜度$O(nlogn)$。

Luogu上還需要輸出方案。

Code:

技術分享圖片
#include <cstdio>
#include <cstring>
#include <algorithm>
using
namespace std; typedef long long ll; const int N = 1e5 + 5; int n, K; ll mn = 0LL, a[N]; template <typename T> inline void read(T &X) { X = 0; char ch = 0; T op = 1; for(; ch > 9 || ch < 0; ch = getchar()) if(ch == -) op = -1; for(; ch >= 0 && ch <=
9; ch = getchar()) X = (X << 3) + (X << 1) + ch - 48; X *= op; } template <typename T> inline void chkMax(T &x, T y) { if(y > x) x = y; } namespace SegT { struct Node { int lc, rc; ll sum, cnt; } s[N * 40]; int root, nodeCnt = 0
; #define lc(p) s[p].lc #define rc(p) s[p].rc #define sum(p) s[p].sum #define cnt(p) s[p].cnt #define mid ((l + r) >> 1) void ins(int &p, ll l, ll r, ll x) { if(!p) p = ++nodeCnt; sum(p) += x, ++cnt(p); if(l == r) return; if(x <= mid) ins(lc(p), l, mid, x); else ins(rc(p), mid + 1, r, x); } void del(int &p, ll l, ll r, ll x) { sum(p) -= x, --cnt(p); if(l == r) return; if(x <= mid) del(lc(p), l, mid, x); else del(rc(p), mid + 1, r, x); } ll getKth(int p, ll l, ll r, int k) { if(l == r) return l; int now = cnt(lc(p)); if(k <= now) return getKth(lc(p), l, mid, k); else return getKth(rc(p), mid + 1, r, k - now); } int qCnt(int p, ll l, ll r, ll x, ll y) { if(x <= l && y >= r) return cnt(p); int res = 0; if(x <= mid) res += qCnt(lc(p), l, mid, x, y); if(y > mid) res += qCnt(rc(p), mid + 1, r, x, y); return res; } ll qSum(int p, ll l, ll r, ll x, ll y) { if(x <= l && y >= r) return sum(p); ll res = 0LL; if(x <= mid) res += qSum(lc(p), l, mid, x, y); if(y > mid) res += qSum(rc(p), mid + 1, r, x, y); return res; } #undef mid } using namespace SegT; int main() { read(n), read(K); for(int i = 1; i <= n; i++) { read(a[i]); chkMax(mn, a[i]); } // ll sum = 0LL; for(int i = 1; i <= K; i++) { // sum += a[i]; ins(root, 0, mn, a[i]); } int pos = 1; ll mid = getKth(root, 0, mn, (K + 1) / 2); ll minCost = mid * qCnt(root, 0, mn, 0, mid) - qSum(root, 0, mn, 0, mid); minCost += qSum(root, 0, mn, mid + 1, mn) - mid * qCnt(root, 0, mn, mid + 1, mn); for(int i = K + 1; i <= n; i++) { del(root, 0, mn, a[i - K]); ins(root, 0, mn, a[i]); ll nowMid = getKth(root, 0, mn, (K + 1) / 2); ll nowCost = nowMid * qCnt(root, 0, mn, 0, nowMid) - qSum(root, 0, mn, 0, nowMid); nowCost += qSum(root, 0, mn, nowMid + 1, mn) - nowMid * qCnt(root, 0, mn, nowMid + 1, mn); if(nowCost < minCost) { pos = i - K + 1; mid = nowMid; minCost = nowCost; } } printf("%lld\n", minCost); /* for(int i = 1; i <= n; i++) { if(i >= pos && i <= pos + K - 1) printf("%lld\n", mid); else printf("%lld\n", a[i]); } */ return 0; }
View Code

Luogu 3466 [POI2008]KLO-Building blocks