1. 程式人生 > >【樹狀數組】【P4113】[HEOI2012]采花

【樹狀數組】【P4113】[HEOI2012]采花

pan namespace cast 多少 desc ++ endif 數字 並且

Description

給定一個長度為 \(n\) 的序列,有 \(m\) 次詢問,每次詢問一段區間,求區間中有多少個數出現次數超過 \(1\)

Limitation

\(n,~m~\leq~2~\times~10^6\)

Solution

好像和大眾做法不大一樣?

考慮對於每個位置,我們記一個 pre 和一個 post,代表他前面最後一個出現這個數的位置和他後面第一個出現這個數的位置。

考慮一個位置 \(x\) 對一個 \([l,~r]\) 的查詢產生貢獻當且僅當 \(pre_x~\geq~l\) 並且 \(post_x~>~r\)

我們發現這個東西是可以樹狀數組維護的。

考慮統計一段區間內 pre

大於等於某個數的個數顯然可以對 pre 開權值樹狀數組,然後按照左端點不升序排序,左端點左移的時候將對應位置的 pre 加入樹狀數組,一次查詢的答案即為 \(BIT_{r}~-~BIT_{l - 1}\)

現在考慮加入 \(post_x ~>~r\) 的限制。

我們發現當且僅當滿足該條件的位置才對答案有貢獻,於是我們只需要保證樹狀數組裏只存有滿足該條件的位置的 pre,就可以統計答案了。考慮按照右端點不升序排序,一開始先將最後一次出現的數字的 pre 加入到樹狀數組中,每次移動右端點的時候,將 post 為右端點所在位置的位置的 pre 加入樹狀數組即可(即將 \(post_x~=~R\)

\(x\) 的對應 \(per_x\) 加入樹狀數組)。由於大於右端點的部分的 pre 對答案同樣沒有貢獻了,所以移動右端點的時候別忘了把右端點對應的 pre 在樹狀數組上刪除。

Code

#include <cstdio>
#include <vector>
#include <algorithm>
#ifdef ONLINE_JUDGE
#define freopen(a, b, c)
#endif

typedef long long int ll;

namespace IPT {
    const int L = 1000000;
    char buf[L], *front=buf, *end=buf;
    char GetChar() {
        if (front == end) {
            end = buf + fread(front = buf, 1, L, stdin);
            if (front == end) return -1;
        }
        return *(front++);
    }
}

template <typename T>
inline void qr(T &x) {
    char ch = IPT::GetChar(), lst = ' ';
    while ((ch > '9') || (ch < '0')) lst = ch, ch=IPT::GetChar();
    while ((ch >= '0') && (ch <= '9')) x = (x << 1) + (x << 3) + (ch ^ 48), ch = IPT::GetChar();
    if (lst == '-') x = -x;
}

namespace OPT {
    char buf[120];
}

template <typename T>
inline void qw(T x, const char aft, const bool pt) {
    if (x < 0) {x = -x, putchar('-');}
    int top=0;
    do {OPT::buf[++top] = static_cast<char>(x % 10 + '0');} while (x /= 10);
    while (top) putchar(OPT::buf[top--]);
    if (pt) putchar(aft);
}

const int maxn = 2000010;

int n, c, m, dn;
int MU[maxn], oc[maxn], pos[maxn], pre[maxn], tree[maxn];
std::vector<int> vc[maxn];

struct Ask {
    int l, r, id, ans;
    
    inline bool operator<(const Ask &_others) const {
        return this->r > _others.r;
    }
};
Ask ask[maxn];
bool cmp(const Ask&, const Ask&);

int lowbit(int);
void update(int, int);
int query(int);

int main() {
    freopen("1.in", "r", stdin);
    qr(n); qr(c); qr(m); dn = n + 1;
    for (int i = 1; i <= n; ++i) {
        qr(MU[i]); pre[i] = oc[MU[i]]; oc[MU[i]] = i;
    }
    for (int i = 1; i <= c; ++i) oc[i] = dn;
    for (int i = n; i; --i) {
        vc[pos[i] = oc[MU[i]]].push_back(i);
        oc[MU[i]] = i;
    }
    for (int i = 1; i <= m; ++i) {
        qr(ask[i].l); qr(ask[i].r); ask[i].id = i;
    }
    std::sort(ask + 1, ask + 1 + m);
    for (auto i : vc[dn]) update(pre[i], 1);
    for (int i = 1, R = n; i <= m; ++i) {
        int l = ask[i].l, r = ask[i].r;
        while (R > r) {
            update(pre[R], -1);
            for (auto j : vc[R]) update(pre[j], 1);
            --R;
        }
        ask[i].ans = query(r) - query(l - 1);
    }
    std::sort(ask + 1, ask + 1 + m, cmp);
    for (int i = 1; i <= m; ++i) {
        qw(ask[i].ans, '\n', true);
    }
    return 0;
}

inline bool cmp(const Ask &_a, const Ask &_b) {
    return _a.id < _b.id;
}

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

void update(int x, int v) {
    if (x == 0) return;
    while (x <= dn) {
        tree[x] += v;
        x += lowbit(x);
    }
}

int query(int x) {
    int _ret = 0;
    while (x) {
        _ret += tree[x];
        x -= lowbit(x);
    }
    return _ret;
}

【樹狀數組】【P4113】[HEOI2012]采花