--- 这里是 cjiaw 的小窝(●'◡'●) ---

正在玩命加载中......

洛谷__P3466 [POI 2008] KLO-Building blocks(平衡树)

在洛谷ac的时候发现在所有提交中跑的较快 ,于是写下这篇博客


题目链接:P3466 [POI 2008] KLO-Building blocks - 洛谷


题目大意:

你有 n 列砖,每列有不同高度,要使连续 k 列高度相同。

两种操作:移除一块砖或增加一块砖。

求最少操作次数及最终每列高度。


思路:

假设已经找到了答案的连续的 k 列砖,

很明显在输出的答案中这 k 列砖高度是相同的某个值 ,其他列的高度还是原来的高度,

要让这 k 列高度一样的最小代价显然是 各自的高度与区间的中位数的差 的和 , ( 此处不证 )

这 k 列高度也就是 区间的中位数

这道题也就变成了求 | 区间各个数 - 区间中位数 |  的最小值,

这里用两个 multiset 来维护区间的中位数,小于等于中位数的放左边的集合,大的放右边的集合

此时,中位数就是 multiset左集合 中的最大值

当滚动区间时,每次都遍历 区间各个数 - 区间中位数 ,此时时间复杂度来到 n*m,(洛谷会T一个点)

我们可以用分别记录 两个集合中的和,

这样,区间各个数 - 区间中位数 =  区间中位数*左集合的size - 左集合之和 + 右集合之和 - 区间中位数 *右集合的size

代码有详细注释


代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<deque>
#include<stack>
#include<set>
#include<map>
#include<unordered_set>
#include<unordered_map>
#include<bitset>
#include<tuple>
#include<array>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/numeric>
#define inf 72340172838076673
#define int long long
#define endl '\n'
#define F first
#define S second
#define mst(a,x) memset(a,x,sizeof (a))
#define gmap __gnu_pbds::gp_hash_table
#define power __gnu_cxx::power
using namespace std;
typedef pair<int, int> pii;

const int N = 100086;
int n, m;
int a[N];

void solve() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> a[i];
    
    multiset<int> l, r;//l存小于等于中位数的值,r反之
    int sl = 0, sr = 0;//左,右集合之和
    int mn = inf, fl, res = 0;
    
    for (int i = 1; i <= n; i++) {
        if (l.empty() || a[i] <= *l.rbegin()) {
            l.insert(a[i]);
            sl += a[i];
        } else {
            r.insert(a[i]);
            sr += a[i];
        }
        
        if (i > m) {//删除超出区间前的数
            int t = a[i - m];
            if (t <= *l.rbegin()) {//根据大小判断在哪个集合
                auto it = l.find(t);
                l.erase(it);
                sl -= t;
            } else {
                auto it = r.find(t);
                r.erase(it);
                sr -= t;
            }
        }
        
        //调整左右集合的长度
        if (l.size() > r.size() + 1) {
            int t = *l.rbegin();
            l.erase(--l.end());
            r.insert(t);
            sl -= t, sr += t;
        } else if (r.size() > l.size()) {
            int t = *r.begin();
            r.erase(r.begin());
            l.insert(t);
            sr -= t, sl += t;
        }
        
        if (i >= m) {
            int mid = *l.rbegin();//当前区间中位数
            int t = mid * l.size() - sl + sr - mid * r.size();
            if (t < mn) {
                mn = t, fl = i, res = mid;
            }
        }
    }
    
    cout << mn << endl;
    for (int i = 1; i <= fl - m; i++) cout << a[i] << endl;
    for (int i = fl - m + 1; i <= fl; i++) cout << res << endl;
    for (int i = fl + 1; i <= n; i++) cout << a[i] << endl;
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);
    
    int T = 1;
    // cin >> T;
    while (T--) solve();
    
    return 0;
}

 

posted @ 2025-12-19 00:13  wwjjw  阅读(27)  评论(0)    收藏  举报