洛谷__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;
}

浙公网安备 33010602011771号