【树状数组】HDU 5381 The sum of gcd

通道

题意:f(l,r)=ri=lrj=igcd(ai,ai+1....aj),q次询问。

思路:考虑每加入一个点,那么贡献了r-l+1个区间,然后会发现区间内与新加入的r这个的gcd都是一块一块的,然后树状数组维护这个即可。

代码:

 

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>

using namespace std;

typedef long long ll;

template <class T>
inline bool rd(T &ret) {
    char c; int sgn;
    if(c = getchar() , c == EOF) return false;
    while(c != '-' && (c < '0' || c > '9')) c = getchar();
    sgn = (c == '-') ? -1 : 1;
    ret = (c == '-') ? 0 : (c - '0');
    while(c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
    ret *= sgn;
    return true;
}

const int MAX_N = 10007;

struct Node {
    int l, r, id;
    bool operator < (const Node &rhs) const {
        return r < rhs.r;
    }
};

int n;
struct Bit {
    ll bit[MAX_N];
    void clear() {
        memset(bit, 0, sizeof bit);
    }
    void add(int i, ll v) {
        if (i == 0) bit[0] += v;
        else {
            for (;i > 0; i -= i & -i)
                bit[i] += v;
        }
    }
    ll query(int i) {
        if (i < 0) return 0;
        else {
            ll re = 0;
            for (;i <= n; i += i & -i)
                re += bit[i];
            return re;
        }
    }
};

ll gcd(ll a, ll b) {
    while (a %= b ^= a ^= b ^= a);
    return b;
}

int a[MAX_N], val[MAX_N], pre[MAX_N];
ll ans[MAX_N];
Node q[MAX_N];
Bit B[2];

void update(int l, int r, ll v) {
    B[0].add(l - 1, v * (r - l + 1));
    B[0].add(r, v * (r + 1));
    B[0].add(l - 1, -v * (r + 1));
    B[1].add(l - 1, -v); B[1].add(r, v); 
}

int main() {
    int T; rd(T);
    while (T-- > 0) {
        rd(n);
        for (int i = 1; i <= n; ++i) rd(a[i]);
        B[0].clear(); B[1].clear();
        int Q; rd(Q);
        for (int i = 0; i < Q; ++i) {
            rd(q[i].l), rd(q[i].r); q[i].id = i;
        }
        sort(q, q + Q);
        int k = 0; val[1] = a[1]; pre[1] = 0;
        update(1, 1, a[1]);
        for (int i = 2; i <= n; ++i) {
            pre[i] = i - 1, val[i] = a[i]; 
            int j = i;
            while (j > 0) {
                val[j] = gcd(val[j], a[i]);
                while (pre[j] > 0 && gcd(val[pre[j]], val[j]) == val[j]) 
                    pre[j] = pre[pre[j]];
                update(pre[j] + 1, j, val[j]);
                j = pre[j];
            }
            while (k < Q && q[k].r == i) 
                ans[q[k].id] = B[0].query(q[k].l) - B[1].query(q[k].l) * q[k++].l;
        }
        for (int i = 0; i < Q; ++i) printf("%I64d\n", ans[i]);
    }
    return 0;
}
View Code

 

posted @ 2015-08-13 21:00  mithrilhan  阅读(264)  评论(0编辑  收藏  举报