[HDU 4777 Rabbit Kingdom] 离线+树状数组

题目

http://acm.hdu.edu.cn/showproblem.php?pid=4777

分析

离线+树状数组

去年现场赛时写了树套树,今天想了想树状数组的做法

首先处理出每个点前面和后面最近的不互质的数的位置,分别记为prev[]和next[]

然后把每个点挂在next[]下面

再把询问离线,挂在右端点上

从1到n枚举i,在i位置+1,在prev[i]位置-1

再把以i为next的点-1,对应的prev位置+1

然后把以这个点为有右端点的询问通过区间和查询即可

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <vector>
using namespace std;

template <class T>
inline void gmax(T &a, T b) {
    if (a < b) {
        a = b;
    }
}

template <class T>
inline void gmin(T &a, T b) {
    if (a > b) {
        a = b;
    }
}

const int MAX_N = 200005;

int cntPrime;
int prime[MAX_N];
int minPrime[MAX_N];
bool isPrime[MAX_N];

int n, m;
int weight[MAX_N];

int c[MAX_N];
int prev[MAX_N];
int next[MAX_N];
int last[MAX_N];

int ans[MAX_N];

vector<int> events[MAX_N];
vector< pair<int, int> > queries[MAX_N];

void makePrime() {
    for (int i = 1; i <= 200000; i++) {
        minPrime[i] = i;
        isPrime[i] = true;
    }
    isPrime[1] = false;
    for (int i = 2; i <= 200000; i++) {
        if (isPrime[i]) {
            prime[cntPrime++] = i;
        }
        for (int j = 0; j < cntPrime && prime[j] * i <= 200000; j++) {
            minPrime[prime[j] * i] = prime[j];
            isPrime[prime[j] * i] = false;
            if (prime[j] == minPrime[i]) {
                break;
            }
        }
    }
}

inline int lowbit(int i) {
    return i & (-i);
}

void add(int x, int val) {
    for (int i = x; i <= n; i += lowbit(i)) {
        c[i] += val;
    }
}

int get(int x) {
    int ret = 0;
    for (int i = x; i; i -= lowbit(i)) {
        ret += c[i];
    }
    return ret;
}

int main() {
//    freopen("in.txt", "r", stdin);
    makePrime();
    while (scanf("%d %d", &n, &m), n || m) {
        for (int i = 1; i <= n; i++) {
            events[i].clear();
            queries[i].clear();
        }

        for (int i = 1; i <= n; i++) {
            scanf("%d", &weight[i]);
        }

        {
            for (int i = 0; i < cntPrime; i++) {
                last[prime[i]] = 0;
            }
            for (int i = 1; i <= n; i++) {
                int x = weight[i];
                prev[i] = 0;
                while (x != 1) {
                    gmax(prev[i], last[minPrime[x]]);
                    x /= minPrime[x];
                }
                x = weight[i];
                while (x != 1) {
                    last[minPrime[x]] = i;
                    x /= minPrime[x];
                }
            }
        }
        {
            for (int i = 0; i < cntPrime; i++) {
                last[prime[i]] = n + 1;
            }
            for (int i = n; i >= 1; i--) {
                int x = weight[i];
                next[i] = n + 1;
                while (x != 1) {
                    gmin(next[i], last[minPrime[x]]);
                    x /= minPrime[x];
                }
                x = weight[i];
                while (x != 1) {
                    last[minPrime[x]] = i;
                    x /= minPrime[x];
                }
            }
        }

        for (int i = 1; i <= n; i++) {
            if (next[i] <= n) {
                events[next[i]].push_back(i);
            }
        }

        for (int i = 1; i <= m; i++) {
            int l, r;
            scanf("%d %d", &l, &r);
            queries[r].push_back(make_pair(l, i));
        }

        memset(c, 0, sizeof(c));
        for (int i = 1; i <= n; i++) {
            add(i, 1);
            if (prev[i]) {
                add(prev[i], -1);
            }
            int cntEvent = (int)events[i].size();
            for (int j = 0; j < cntEvent; j++) {
                int x = events[i][j];
                add(x, -1);
                if (prev[x]) {
                    add(prev[x], 1);
                }
            }
            int cntQuery = (int)queries[i].size();
            for (int j = 0; j < cntQuery; j++) {
                ans[queries[i][j].second] = get(i) - get(queries[i][j].first - 1);
            }
        }

        for (int i = 1; i <= m; i++) {
            printf("%d\n", ans[i]);
        }
    }
    return 0;
}



你可能感兴趣的:([HDU 4777 Rabbit Kingdom] 离线+树状数组)