Cod sursa(job #1154628)

Utilizator beldeabogdanBogdan Beldea beldeabogdan Data 26 martie 2014 11:48:52
Problema Arbori indexati binar Scor 0
Compilator cpp Status done
Runda Arhiva educationala Marime 2.21 kb
#include <cstdio>
#include <algorithm>
#include <set>
#define minim(a,b) (a<b)?(a):(b)
#define nmax 100005
#define lsb(a) (a&(-a))
#define llinf 0xffffffffffffffffLL
using namespace std;

int v[nmax],a[nmax],vn[nmax];
int tree[nmax];
int ktree[nmax];
int n,k,ap;
unsigned long long minsum = llinf;

int kQuery(int pos) {
    int r = 0;
    while (pos > 0) {
        r += ktree[pos];
        pos -= lsb(pos);
    }
    return r;
}

int ktreeSearch(int a) {
    int start=1;
    while (1 << start <= n && kQuery(1 << start) <= a) start += 1;
    start -= 1;
    int conf = 1<<start;
    for (int i=start-1;i>=0;i--) {
        if (conf+(1<<i) <= n && kQuery(conf+(1<<i)) <= a) conf += 1<<i;
    }
    return conf;
}

void update(int pos,int val) {
    while (pos <= n) {
        ktree[pos] += (val>=0)?(1):(-1);
        tree[pos] += val;
        pos += lsb(pos);
    }
}

int query(int pos) {
    int sum = 0;
    while (pos > 0) {
        sum += tree[pos];
        pos -= lsb(pos);
    }
    return sum;
}

int binarysearch(int val) {
    int s = 1,f = ap;
    while (s <= f) {
        int mij = (s+f)/2;
        if (val < a[mij]) f = mij-1;
        else if (a[mij] == val) return mij;
        else s = mij+1;
    }
    return s;
}

int main() {
    freopen("pikachu.in","r",stdin);
    freopen("pikachu.out","w",stdout);
    scanf("%d %d ",&n,&k);
    for (int i=1;i<=n;i++) {
        scanf("%d",&v[i]);
        a[i] = v[i];
    }
    sort(a+1,a+n+1);
    for (int i=1;i<=n;i++) if (a[i] != a[i+1]) a[++ap] = a[i];
    for (int i=1;i<=n;i++)
        vn[i] = binarysearch(v[i]);
    int total = 0;
    for (int i=1;i<=k;i++) {
        total += v[i];
        update(vn[i],v[i]);
    }
    for (int i=k+1;i<=n+1;i++) {
        int medianpos = ktreeSearch(k/2+1);
        int median = a[medianpos];
        long long left = query(medianpos);
        long long right = total - left;
        long long newsum = (2*(k/2+1)-k)*median - left + right;
        minsum = minim(minsum,newsum);
        total += v[i] - v[i-k];
        if (i <= n) {
            update(vn[i-k],-v[i-k]);
            update(vn[i],v[i]);
        }
    }
    printf("%llu\n",minsum);
    return 0;
}