标签:query 前缀 前向星 影响 algorithm upd ons sort 数字
给一段长度n(n<=100000)序列,每次询问一段区间(个数<=200000),问区间中的数字种数。
本题特别之处在于区间内的数字种数不满足区间的相加性,所以我们可以加约束条件。我们不妨考虑维护一个树状数组维护数字种数。显然当询问的r固定时,对于每一个数值,我们只保留其在[1,r]内最右侧的数字,将其它数字删除,这样对结果没有影响,反而数字的个数满足区间可加性了。所以定义树状数组维护的前缀和值为满足约束条件——对于每个数值只保留位置最右侧的数字——时,[1,r]中仍然存在的数字的个数。
因此,我们将所有询问按照右端点排序,当树状数组负责的右端点要向右延伸时,要在树状数组中把右端点的数值与其相等、位置位于它左侧的位置(解决的办法貌似叫做“链式前向星”?)对应前缀和更新-1,将右端点所在位置对应前缀和更新+1即可。
一定要注意查询是排过序的,输出时要按照原有的顺序输出!!!!!
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int MAX_LEN = 500010, MAX_VAL = 1000010, MAX_QUERY = 200010; int OrgData[MAX_LEN], EqValPrev[MAX_LEN]; int Len, TotQuery; struct BIT { private: int C[MAX_LEN]; int N; int Lowbit(int x) { return x & -x; } public: BIT(int n):N(n){} void Update(int p, int val) { if (p == 0) return; while (p <= N) { C[p] += val; p += Lowbit(p); } } int Query(int p) { int ans = 0; while (p >= 1) { ans += C[p]; p -= Lowbit(p); } return ans; } }; struct Query { int L, R, Ans; }_qs[MAX_QUERY], *SortedQ[MAX_QUERY]; bool Cmp_R(Query *a, Query *b) { return a->R < b->R; } void GetEqValPrev() { static int valPrev[MAX_VAL]; for (int i = 1; i <= Len; i++) { EqValPrev[i] = valPrev[OrgData[i]]; valPrev[OrgData[i]] = i; } } int main() { scanf("%d", &Len); for (int i = 1; i <= Len; i++) scanf("%d", OrgData + i); scanf("%d", &TotQuery); for (int i = 1; i <= TotQuery; i++) scanf("%d%d", &_qs[i].L, &_qs[i].R); static BIT g(Len); for (int i = 1; i <= TotQuery; i++) SortedQ[i] = _qs + i; sort(SortedQ + 1, SortedQ + TotQuery + 1, Cmp_R); GetEqValPrev(); int curR = 0; for (int i = 1; i <= TotQuery; i++) { while (curR < SortedQ[i]->R) { curR++; g.Update(EqValPrev[curR], -1); g.Update(curR, 1); } SortedQ[i]->Ans = g.Query(SortedQ[i]->R) - g.Query(SortedQ[i]->L - 1); } for (int i = 1; i <= TotQuery; i++) printf("%d\n", _qs[i].Ans); return 0; }
标签:query 前缀 前向星 影响 algorithm upd ons sort 数字
原文地址:https://www.cnblogs.com/headboy2002/p/9488711.html