[bzoj1112] [tree array] brick Klo

Description

N-pillar brick, the height of continuous K-pillar is the same. You can choose the following two actions 1: take a brick from the top of a pillar brick, and discard it
2: Take a brick out of the warehouse and put it on another column. The warehouse is infinite. Now I want to finish the task with the minimum number of actions

Input

The first line gives N,K. (1 ≤ k ≤ n ≤ 100000), and the next N lines represent the height of the column brick. 0 ≤ hi ≤ 1000000

Output

Minimum number of actions

Sample Input

5 3

3

9

2

3

1

Sample Output

2

HINT

The original question also requires the height of each column brick when the output is finished

Title Solution

You can see that for a continuous segment, put that segment on the number axis. Then find a point on the number axis to minimize the total distance from this number to this point
It's not hard to think of this as the median
So we can enumerate each segment and find it in the tree array
And then it's gone..

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
LL a[1110000],mmax;
int s[1110000],n,K;
int lowbit(int x){return x&-x;}
void chs(int x,int c){while(x<=mmax){s[x]+=c;x+=lowbit(x);}}
void cha(int x,LL c){while(x<=mmax){a[x]+=c;x+=lowbit(x);}}
LL findsum(int x){LL ret=0;while(x>=1){ret+=a[x];x-=lowbit(x);}return ret;}
int findall(int x){int ret=0;while(x>=1){ret+=s[x];x-=lowbit(x);}return ret;}
LL h[1110000];
int main()
{
    scanf("%d%d",&n,&K);
    mmax=0;
    for(int i=1;i<=n;i++)scanf("%lld",&h[i]),h[i]++,mmax=max(mmax,h[i]);
    for(int i=1;i<K;i++)cha(h[i],h[i]),chs(h[i],1);
    LL owb=1000000000000000000;
    int mid=K/2+1;
    for(int i=K;i<=n;i++)
    {
        cha(h[i],h[i]);chs(h[i],1);
        if(i-K>=1)cha(h[i-K],-h[i-K]),chs(h[i-K],-1);
        int cnt=0,ans=0;
        for(int j=(1<<21);j;j>>=1)if(ans+s[cnt+j]<mid && cnt+j<=mmax)ans+=s[cnt+j],cnt+=j;
        cnt++;
        int sum=findall(cnt-1);
        LL tmp=(LL)cnt*sum-findsum(cnt-1);
        sum=findall(mmax)-findall(cnt);
        tmp+=findsum(mmax)-findsum(cnt)-(LL)cnt*sum;
        owb=min(owb,tmp);
    }
    printf("%lld\n",owb);
    return 0;
}

Posted by ltbaggz on Wed, 01 Apr 2020 21:15:22 -0700