【樹狀數組】【P4113】[HEOI2012]采花
阿新 • • 發佈:2019-03-11
pan namespace cast 多少 desc ++ endif 數字 並且 大於等於某個數的個數顯然可以對 的 \(x\) 的對應 \(per_x\) 加入樹狀數組)。由於大於右端點的部分的
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\)
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]采花