BZOJ 1112: [POI2008]砖块Klo1112( BST )
枚举每个长度为k的区间, 然后用平衡树找中位数进行判断, 时间复杂度O(nlogn).
早上起来精神状态不太好...连平衡树都不太会写了...果断去看了会儿番然后就A了哈哈哈
--------------------------------------------------------------------------
#include<bits/stdc++.h>
#define rep(i, n) for(int i = 0; i < n; i++)
#define clr(x, c) memset(x, c, sizeof(x))
using namespace std;
typedef long long ll;
const int maxn = 100009;
const int inf = 10000000;
int n, k;
struct Node {
Node *ch[2], *p;
int s, v;
ll sum;
inline void setc(Node* t, int d) {
ch[d] = t;
t->p = this;
}
inline bool d() {
return this == p->ch[1];
}
inline void upd() {
s = ch[0]->s + ch[1]->s + 1;
sum = ch[0]->sum + ch[1]->sum + v;
}
} pool[maxn], *pt = pool, *root, *null;
Node* newNode(int v) {
pt->p = pt->ch[0] = pt->ch[1] = null;
pt->s = 1;
pt->v = pt->sum = v;
return pt++;
}
void init() {
null = pt++;
null->s = null->sum = null->v = 0;
null->ch[0] = null->ch[1] = null->p = null;
root = newNode(inf);
root->setc(newNode(-inf), 0);
root->upd();
}
void rot(Node* t) {
Node* p = t->p;
int d = t->d();
p->p->setc(t, p->d());
p->setc(t->ch[d ^ 1], d);
t->setc(p, d ^ 1);
p->upd();
if(root == p) root = t;
}
void splay(Node* t, Node* f = null) {
while(t->p != f) {
if(t->p->p != f)
t->d() != t->p->d() ? rot(t) : rot(t->p);
rot(t);
}
t->upd();
}
Node* select(int k) {
for(Node* t = root; ;) {
int s = t->ch[0]->s;
if(k == s) return t;
if(k > s)
t = t->ch[1], k -= s + 1;
else
t = t->ch[0];
}
}
int rank(int v) {
int ans = 0;
for(Node* t = root; t != null;) {
if(t->v < v)
ans += t->ch[0]->s + 1, t = t->ch[1];
else
t = t->ch[0];
}
return ans;
}
void insert(int v) {
int r = rank(v);
Node *L = select(r - 1), *R = select(r);
splay(L), splay(R, L);
R->setc(newNode(v), 0);
R->upd(), L->upd();
}
void del(int v) {
int r = rank(v);
Node *L = select(r - 1), *R = select(r + 1);
splay(L), splay(R, L);
R->setc(null, 0);
R->upd(), L->upd();
}
ll work() {
Node *L = select(0), *R = select(k + 1), *t = select((k >> 1) + 1);
splay(L), splay(R, L);
splay(t, R);
return t->v * (t->ch[0]->s - t->ch[1]->s) + t->ch[1]->sum - t->ch[0]->sum;
}
int A[maxn];
int main() {
freopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);
init();
ll ans;
cin >> n >> k;
rep(i, n) {
scanf("%d", A + i);
if(i < k) insert(A[i]);
}
ans = work();
for(int i = k; i < n; i++) {
insert(A[i]);
del(A[i - k]);
ans = min(ans, work());
}
cout << ans << "\n";
return 0;
}
--------------------------------------------------------------------------
1112: [POI2008]砖块Klo
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1288 Solved: 444
[Submit][Status][Discuss]
Description
N柱砖,希望有连续K柱的高度是一样的. 你可以选择以下两个动作 1:从某柱砖的顶端拿一块砖出来,丢掉不要了. 2:从仓库中拿出一块砖,放到另一柱.仓库无限大. 现在希望用最小次数的动作完成任务.
Input
第一行给出N,K. (1 ≤ k ≤ n ≤ 100000), 下面N行,每行代表这柱砖的高度.0 ≤ hi ≤ 1000000
Output
最小的动作次数
Sample Input
5 3
3
9
2
3
1
3
9
2
3
1
Sample Output
2
HINT
原题还要求输出结束状态时,每柱砖的高度.本题略去.
Source