Description
给定序列
a
=
(
a
1
,
a
2
,
⋯
,
a
n
)
a=(a_1,a_2,\cdots,a_n)
a=(a1,a2,⋯,an).
定义
f
(
l
,
r
)
=
∣
{
a
i
:
i
∈
[
l
,
r
]
}
∣
f(l,r)=|\{a_i:i\in[l,r]\}|
f(l,r)=∣{ai:i∈[l,r]}∣.
给定
m
m
m 次询问
(
l
,
r
)
(l,r)
(l,r),你要求出
∑
l
≤
s
≤
t
≤
r
(
f
(
s
,
t
)
m
o
d
2
)
\sum\limits_{l\le s\le t\le r}(f(s,t)\bmod 2)
l≤s≤t≤r∑(f(s,t)mod2).
Limitations
1
≤
n
,
m
≤
10
6
1\le n,m\le 10^6
1≤n,m≤106
1
≤
a
i
,
l
,
r
≤
n
1\le a_i,l,r\le n
1≤ai,l,r≤n
3
s
,
512
MB
3\text{s},512\text{MB}
3s,512MB
Solution
在线做是做不了的,离线下来,挂在
r
r
r 上扫描线.
设
l
s
t
i
lst_i
lsti 表示
i
i
i 前上一个
a
i
a_i
ai 的出现位置.
考虑加入
a
i
a_i
ai 后的影响,区间
[
l
,
i
]
[l,i]
[l,i] 的颜色数奇偶性会改变,其中
l
∈
(
l
s
t
i
,
i
]
l\in(lst_i,i]
l∈(lsti,i].
显然这就是历史和,现在只需一个支持区间异或
1
1
1,区间历史和的 ds
.
考虑线段树,节点上维护
1
1
1 的个数
cnt
\textit{cnt}
cnt 与历史和
his
\textit{his}
his,以及异或标记
rev
\textit{rev}
rev 与
0
/
1
0/1
0/1 的历史和更新标记
tag
0
/
1
\textit{tag}_{0/1}
tag0/1.
这些都是容易直接维护的(具体见代码),于是做完了,时间复杂度
O
(
(
n
+
m
)
log
n
)
O((n+m)\log n)
O((n+m)logn).
注意要先下传异或标记,否则答案会错,以及开 long long
和常数问题.
Code
3.64 KB , 11.96 s , 153.59 MB (in total, C++20 with O2) 3.64\text{KB},11.96\text{s},153.59\text{MB}\;\texttt{(in total, C++20 with O2)} 3.64KB,11.96s,153.59MB(in total, C++20 with O2)
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
using ui64 = unsigned long long;
using i128 = __int128;
using ui128 = unsigned __int128;
using f4 = float;
using f8 = double;
using f16 = long double;
template<class T>
bool chmax(T &a, const T &b){
if(a < b){ a = b; return true; }
return false;
}
template<class T>
bool chmin(T &a, const T &b){
if(a > b){ a = b; return true; }
return false;
}
namespace fastio {} // By pystraf
using fastio::read;
using fastio::write;
namespace seg_tree {
inline int ls(int u) { return 2 * u + 1; }
inline int rs(int u) { return 2 * u + 2; }
struct Node {
int l, r, len, cnt;
i64 his, tag0 = 0, tag1 = 0;
bool rev = false;
};
struct SegTree {
vector<Node> tr;
inline SegTree() {}
inline SegTree(int n) : tr(n << 1) { build(0, 0, n - 1); }
inline void pushup(int u, int mid) {
tr[u].his = tr[ls(mid)].his + tr[rs(mid)].his;
tr[u].cnt = tr[ls(mid)].cnt + tr[rs(mid)].cnt;
}
inline void neg(int u) {
tr[u].rev ^= 1;
swap(tr[u].tag0, tr[u].tag1);
tr[u].cnt = tr[u].len - tr[u].cnt;
}
inline void apply(int u, i64 t0, i64 t1) {
tr[u].his += t1 * tr[u].cnt + t0 * (tr[u].len - tr[u].cnt);
tr[u].tag0 += t0, tr[u].tag1 += t1;
}
inline void pushdown(int u, int mid) {
if (tr[u].rev) {
neg(ls(mid)), neg(rs(mid));
tr[u].rev = false;
}
if (tr[u].tag0 == 0 && tr[u].tag1 == 0) return;
apply(ls(mid), tr[u].tag0, tr[u].tag1);
apply(rs(mid), tr[u].tag0, tr[u].tag1);
tr[u].tag0 = tr[u].tag1 = 0;
}
void build(int u, int l, int r) {
tr[u].l = l, tr[u].r = r;
tr[u].len = r - l + 1;
if (l == r) return;
const int mid = (l + r) >> 1;
build(ls(mid), l, mid), build(rs(mid), mid + 1, r);
}
void negate(int u, int l, int r) {
if (l > r) return;
if (l <= tr[u].l && tr[u].r <= r) return neg(u);
const int mid = (tr[u].l + tr[u].r) >> 1;
pushdown(u, mid);
if (l <= mid) negate(ls(mid), l, r);
if (r > mid) negate(rs(mid), l, r);
pushup(u, mid);
}
i64 query(int u, int l, int r) {
if (l <= tr[u].l && tr[u].r <= r) return tr[u].his;
const int mid = (tr[u].l + tr[u].r) >> 1;
i64 res = 0;
pushdown(u, mid);
if (l <= mid) res += query(ls(mid), l, r);
if (r > mid) res += query(rs(mid), l, r);
return res;
}
};
}
using seg_tree::SegTree;
using pii = pair<int, int>;
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
const int n = read<int>();
vector<int> a(n), lst(n), mp(n, -1);
for (int i = 0; i < n; i++) {
a[i] = read<int>(), a[i]--;
lst[i] = mp[a[i]];
mp[a[i]] = i;
}
const int m = read<int>();
vector<vector<pii>> adj(n);
for (int i = 0, l, r; i < m; i++) {
l = read<int>(), r = read<int>(), l--, r--;
adj[r].emplace_back(l, i);
}
SegTree sgt(n);
vector<i64> ans(m);
for (int i = 0; i < n; i++) {
sgt.negate(0, lst[i] + 1, i);
sgt.apply(0, 0, 1);
for (auto [j, id] : adj[i]) ans[id] = sgt.query(0, j, i);
}
for (int i = 0; i < m; i++) {
write(ans[i]);
putchar_unlocked('\n');
}
return 0;
}