bzoj 2743 [HEOI2012]采花 离线处理+树状数组

题面

题目传送门

解法

\(nxt_i\)\(a_i\)下一次出现的位置

把所有询问按左端点排序

处理完所有以\(i\)开始的询问后,我们把\(nxt_i\)的影响删除,把\(nxt_{nxt_i}\)加上

这样就能保证计算入答案的必然是这个区间里第二次出现的

树状数组维护即可

时间复杂度:\(O(q\ log\ q+q\ log\ n)\)

代码

#include <bits/stdc++.h>
#define N 2000010
using namespace std;
template <typename node> void read(node &x) {
    x = 0; int f = 1; char c = getchar();
    while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
    while (isdigit(c)) x = x * 10 + c - '0', c = getchar(); x *= f;
}
struct Node {
    int l, r, id;
    bool operator < (const Node &a) const {
        return l < a.l;
    }
} b[N];
int n, c, q, a[N], f[N], s[N], ans[N], las[N], nxt[N], tmp[N];
int lowbit(int x) {return x & -x;}
void modify(int x, int val) {
    for (int i = x; i <= n; i += lowbit(i))
        f[i] += val;
}
int query(int x) {
    int ret = 0;
    for (int i = x; i; i -= lowbit(i)) ret += f[i];
    return ret;
}
int main() {
    read(n), read(c), read(q);
    for (int i = 1; i <= n; i++) read(a[i]);
    for (int i = n; i; i--) nxt[i] = las[a[i]], las[a[i]] = i;
    for (int i = 1; i <= c; i++)
        if (nxt[las[i]]) modify(nxt[las[i]], 1);
    for (int i = 1; i <= q; i++) read(b[i].l), read(b[i].r), b[i].id = i;
    sort(b + 1, b + q + 1); int now = 1;
    for (int i = 1; i <= q; i++) {
        while (now < b[i].l) {
            if (nxt[now]) modify(nxt[now], -1);
            if (nxt[nxt[now]]) modify(nxt[nxt[now]], 1);
            now++;
        }
        ans[b[i].id] = query(b[i].r) - query(b[i].l - 1);
    }
    for (int i = 1; i <= q; i++) cout << ans[i] << "\n";
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/copperoxide/p/9478724.html