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
Sample Output
2
HINT
原题还要求输出结束状态时,每柱砖的高度.本题略去.
Source
Solution
妈丫BZOJ3224的$treap$调不出来只好另做一道$treap$简单题练手了。
欸这道题还能用树状数组做么?本蒟蒻不会丫。
这道题很容易想到,对于每一个区间,将区间内所有数改成该区间的中位数时开销最小。
找中位数就是找第$(k+1)/2$的数$mid$嘛,于是一个$treap$的做法就诞生了。
滑动窗口,每次保留$k$个数,求出比$mid$小的所有数的和$sum1$以及比$mid$大的所有数的和$sum2$
答案就是$(sum1-(比mid小的数的个数)*mid)+((比mid大的数的个数)*mid-sum2)$
欸好像可以化简,可以化简成$sum2-sum1$,$k$是偶数时多减一个$mid$
普通$treap$,记一个$siz$和一个$sum$即可。
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 struct treap 5 { 6 int l, r, siz, val, pri; 7 ll key, sum; 8 }a[100005]; 9 int root, ptot, h[100005]; 10 ll sum1, sum2; 11 12 void push_up(int k) 13 { 14 a[k].siz = a[a[k].l].siz + a[a[k].r].siz + a[k].val; 15 a[k].sum = a[a[k].l].sum + a[a[k].r].sum + a[k].key * a[k].val; 16 } 17 18 void lturn(int &k) 19 { 20 int tmp = a[k].r; 21 a[k].r = a[tmp].l, a[tmp].l = k; 22 a[tmp].siz = a[k].siz, a[tmp].sum = a[k].sum; 23 push_up(k), k = tmp; 24 } 25 26 void rturn(int &k) 27 { 28 int tmp = a[k].l; 29 a[k].l = a[tmp].r, a[tmp].r = k; 30 a[tmp].siz = a[k].siz, a[tmp].sum = a[k].sum; 31 push_up(k), k = tmp; 32 } 33 34 void insert(int &k, int x) 35 { 36 if(!k) 37 { 38 k = ++ptot, a[k].siz = a[k].val = 1; 39 a[k].sum = a[k].key = x, a[k].pri = rand(); 40 return; 41 } 42 a[k].siz++, a[k].sum += x; 43 if(x == a[k].key) a[k].val++; 44 else if(x < a[k].key) 45 { 46 insert(a[k].l, x); 47 if(a[k].pri < a[a[k].l].pri) rturn(k); 48 } 49 else 50 { 51 insert(a[k].r, x); 52 if(a[k].pri < a[a[k].r].pri) lturn(k); 53 } 54 } 55 56 void del(int &k, int x) 57 { 58 if(!k) return; 59 if(x == a[k].key) 60 if(a[k].val > 1) a[k].val--, a[k].siz--, a[k].sum -= x; 61 else if(!(a[k].l * a[k].r)) k = a[k].l + a[k].r; 62 else if(a[a[k].l].pri < a[a[k].r].pri) lturn(k), del(k, x); 63 else rturn(k), del(k, x); 64 else if(x < a[k].key) a[k].siz--, a[k].sum -= x, del(a[k].l, x); 65 else a[k].siz--, a[k].sum -= x, del(a[k].r, x); 66 } 67 68 int query_num(int k, int x) 69 { 70 if(!k) return 0; 71 if(x <= a[a[k].l].siz) 72 { 73 sum2 += a[a[k].r].sum + a[k].key * a[k].val; 74 return query_num(a[k].l, x); 75 } 76 if(x <= a[a[k].l].siz + a[k].val) 77 { 78 sum1 += a[a[k].l].sum + (x - a[a[k].l].siz - 1) * a[k].key; 79 sum2 += a[a[k].r].sum + (a[a[k].l].siz + a[k].val - x) * a[k].key; 80 return a[k].key; 81 } 82 sum1 += a[a[k].l].sum + a[k].key * a[k].val; 83 return query_num(a[k].r, x - a[a[k].l].siz - a[k].val); 84 } 85 86 int main() 87 { 88 int n, k, mid; 89 ll ans = 100000000000000LL; 90 cin >> n >> k, srand(n); 91 for(int i = 1; i <= n; i++) 92 cin >> h[i]; 93 for(int i = 1; i <= k; i++) 94 insert(root, h[i]); 95 for(int i = k + 1; i <= n + 1; i++) 96 { 97 sum1 = sum2 = 0; 98 mid = query_num(root, (k + 1) >> 1); 99 ans = min(ans, sum2 - sum1 - !(k & 1) * mid); 100 insert(root, h[i]), del(root, h[i - k]); 101 } 102 cout << ans << endl; 103 return 0; 104 }
时间: 2024-10-10 23:55:39