【主席树】bzoj1112: [POI2008]砖块Klo

数据结构划一下水

Description

N柱砖,希望有连续K柱的高度是一样的. 你可以选择以下两个动作 1:从某柱砖的顶端拿一块砖出来,丢掉不要了. 2:从仓库中拿出一块砖,放到另一柱.仓库无限大. 现在希望用最小次数的动作完成任务.

Input

第一行给出N,K. (1 ≤ k ≤ n ≤ 100000), 下面N行,每行代表这柱砖的高度.0 ≤ hi ≤ 1000000

Output

最小的动作次数


 

题目大意

有一个非负的数列,可以±1修改高度,求最小代价使得连续k个高度相同

题目分析

对于一个区间的答案,就相当于把所有数都放在数轴上,再求一个数使得它到所有数的总和最小。那么最优就等于是求一个区间的中位数。

于是问题相当于一个支持  求中位数;求比中位数小/大的数个数;求比中位数小/大的数总和  的数据结构。这个问题可以用主席树在$logn$内完成。

注意 printf(calc(),a,b) ,如果在calc()中改变了a,b,输出的a,b将会是改变之前的值。

 1 #include<bits/stdc++.h>
 2 typedef long long ll;
 3 const int maxn = 100035;
 4 const int maxNode = 4000035;
 5 
 6 struct node
 7 {
 8     int val,l,r;
 9     ll sum;
10 }a[maxNode];
11 ll ans,lsum,rsum,lcnt,rcnt;
12 int n,k;
13 int rt[maxn],w[maxn],cnt[maxn],tot;
14 
15 int read()
16 {
17     char ch = getchar();
18     int num = 0, fl = 1;
19     for (; !isdigit(ch); ch=getchar())
20         if (ch=='-') fl = -1;
21     for (; isdigit(ch); ch=getchar())
22         num = (num<<1)+(num<<3)+ch-48;
23     return num*fl;
24 }
25 void build(int &rt, int l, int r)
26 {
27     rt = ++tot;
28     if (l==r) return;
29     int mid = (l+r)>>1;
30     build(a[rt].l, l, mid);
31     build(a[rt].r, mid+1, r);
32 }
33 void update(int pre, int &rt, int l, int r, int c)
34 {
35     rt = ++tot, a[rt] = a[pre], ++a[rt].val, a[rt].sum += cnt[c];
36     if (l==r) return;
37     int mid = (l+r)>>1;
38     if (c <= mid) update(a[pre].l, a[rt].l, l, mid, c);
39     else update(a[pre].r, a[rt].r, mid+1, r, c);
40 }
41 int query(int pre, int rt, int l, int r, int k)
42 {
43     if (l==r) return l;
44     int val = a[a[rt].l].val-a[a[pre].l].val, mid = (l+r)>>1;
45     if (val >= k){
46         lcnt -= a[a[rt].r].val-a[a[pre].r].val;
47         lsum -= a[a[rt].r].sum-a[a[pre].r].sum;
48         return query(a[pre].l, a[rt].l, l, mid, k);
49     }
50     rcnt -= a[a[rt].l].val-a[a[pre].l].val;
51     rsum -= a[a[rt].l].sum-a[a[pre].l].sum;
52     return query(a[pre].r, a[rt].r, mid+1, r, k-val);
53 }
54 int main()
55 {
56     n = read(), k = read(), ans = 1ll<<60;
57     for (int i=1; i<=n; i++) w[i] = cnt[i] = read();
58     std::sort(cnt+1, cnt+n+1);
59     cnt[0] = std::unique(cnt+1, cnt+n+1)-cnt-1;
60     build(rt[0], 1, cnt[0]);
61     for (int i=1; i<=n; i++)
62     {
63         w[i] = std::lower_bound(cnt+1, cnt+cnt[0]+1, w[i])-cnt;
64         update(rt[i-1], rt[i], 1, cnt[0], w[i]);
65     }
66     for (int r=k; r<=n; r++)
67     {
68         int l = r-k;
69         lcnt = rcnt = a[rt[r]].val-a[rt[l]].val, lsum = rsum = a[rt[r]].sum-a[rt[l]].sum;
70         int tmp = cnt[query(rt[l], rt[r], 1, cnt[0], (k+1)>>1)];
71         ans = std::min(ans, 1ll*tmp*(lcnt-rcnt)-lsum+rsum);
72     }
73     printf("%lld\n",ans);
74     return 0;
75 }

 

 

 

END

posted @ 2019-01-10 16:25  AntiQuality  阅读(144)  评论(0编辑  收藏  举报