Description
给定序列 a=(a1,a2,⋯ ,an)a=(a_1,a_2,\cdots,a_n)a=(a1,a2,⋯,an).
定义 f(l,r)=∣{ai:i∈[l,r]}∣f(l,r)=|\{a_i:i\in[l,r]\}|f(l,r)=∣{ai:i∈[l,r]}∣.
给定 mmm 次询问 (l,r)(l,r)(l,r),你要求出 ∑l≤s≤t≤r(f(s,t) mod 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≤1061\le n,m\le 10^61≤n,m≤106
1≤ai,l,r≤n1\le a_i,l,r\le n1≤ai,l,r≤n
3s,512MB3\text{s},512\text{MB}3s,512MB
Solution
在线做是做不了的,离线下来,挂在 rrr 上扫描线.
设 lstilst_ilsti 表示 iii 前上一个 aia_iai 的出现位置.
考虑加入 aia_iai 后的影响,区间 [l,i][l,i][l,i] 的颜色数奇偶性会改变,其中 l∈(lsti,i]l\in(lst_i,i]l∈(lsti,i].
显然这就是历史和,现在只需一个支持区间异或 111,区间历史和的 ds
.
考虑线段树,节点上维护 111 的个数 cnt\textit{cnt}cnt 与历史和 his\textit{his}his,以及异或标记 rev\textit{rev}rev 与 0/10/10/1 的历史和更新标记 tag0/1\textit{tag}_{0/1}tag0/1.
这些都是容易直接维护的(具体见代码),于是做完了,时间复杂度 O((n+m)logn)O((n+m)\log n)O((n+m)logn).
注意要先下传异或标记,否则答案会错,以及开 long long
和常数问题.
Code
3.64KB,11.96s,153.59MB (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;
}