【分块】Codeforces 86d Powerful array

通道

题意:询问[l,r]区间的权和,权定义为sum(k^2*a[i]),k表示a[i]出现的次数

思路:区间每增加一个a[i],增量是(2*x+1)*a[i],因为(x+1)^2*a[i] = (x^2 +2*x + 1)*a[i]

分块排序即可,块内按r排序

代码:

#include <cstdio>
#include <algorithm>
#include <cmath>

using namespace std;

#define N 200100
typedef long long ll;

ll a[N], cnt[N*5], ans[N], res;
int L, R;

struct node {
    int x, y, l, p;
} q[N];
bool cmp(const node &x, const node &y) {
    if (x.l == y.l) return x.y < y.y;
    return x.l < y.l;
}
void query(int x, int y, int flag) {
    if (flag) {
        for (int i=x; i<L; i++) {
            res += ((cnt[a[i]]<<1)+1)*a[i];
            cnt[a[i]]++;
        } 
        for (int i=R+1; i<=y; i++) {
            res += ((cnt[a[i]]<<1)+1)*a[i];
            cnt[a[i]]++;
        }
        for (int i=L; i<x; i++) {
            cnt[a[i]]--;
            res -= ((cnt[a[i]]<<1)+1)*a[i];
        }
        for (int i=y+1; i<=R; i++) {
            cnt[a[i]]--;
            res -= ((cnt[a[i]]<<1)+1)*a[i];
        }
    } else {
        for (int i=x; i<=y; i++) {
            res += ((cnt[a[i]]<<1)+1)*a[i];
            cnt[a[i]]++;
        }
    }
    L = x, R = y;
}
int main() {
    int n, t;
    scanf("%d%d", &n, &t);
    for (int i=1; i<=n; i++) scanf("%I64d", &a[i]);
    int block_size = sqrt(n);
    for (int i=0; i<t; i++) {
        scanf("%d%d", &q[i].x, &q[i].y);
        q[i].l = q[i].x / block_size;
        q[i].p = i;
    }
    sort(q, q+t, cmp);
    for (int i=0; i<t; i++) {
        query(q[i].x, q[i].y, i);
        ans[q[i].p] = res;
    }
    for (int i=0; i<t; i++) printf("%I64d\n", ans[i]);
    return 0;
}
View Code

 

posted @ 2015-08-17 18:20  mithrilhan  阅读(159)  评论(0编辑  收藏  举报