CFgym103069G Prof. Pang's sequence 题解
Statement
给定长为 \(n\) 的序列 \(a\)。\(m\) 次询问,每次询问给定 \(l,r\),求满足 \(l\le i\le j\le r\) 且 \(a_i,a_{i+1},\cdots,a_j\) 里不同的数的个数为奇数的数对 \((i,j)\) 的个数。
Solution
算是典题。
将询问离线,从左往右扫,考虑“贡献”\(c\) 的变化:

可以发现扫到 \(i\) 时的贡献就是在 \(i-1\) 的基础上将 \([pre_i+1,i]\) 这个区间反转。答案就是“历史和”\(b\) 的区间和。
考虑用线段树维护,要维护当前的和 \(sum\)、历史和 \(his\)、反转标记 \(rtag\)、区间历史和加 \(atag_1\) 次 \(c\) 的标记 \(atag_1\)、区间历史和加 \(atag_2\) 次 \(\operatorname{rev}(c)\) 的标记 \(atag_2\)。
Code
#include <algorithm>
#include <cstdio>
using namespace std;
typedef long long ll;
const int N = 5e5;
struct Node {
ll sum, his;
int rtag, atag1, atag2;
};
struct Query {
int l, r, id;
};
int n, m, a[N + 10], pre[N + 10], pos[N + 10];
Query q[N + 10];
ll ans[N + 10];
Node t[N * 4 + 10];
char gc() {
static char buf[1000000], *p1, *p2;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin)), p1 == p2 ? EOF : *p1++;
}
int read() {
int res = 0; char c = gc();
while (c < '0' || c > '9') c = gc();
while (c >= '0' && c <= '9') res = res * 10 + c - 48, c = gc();
return res;
}
#define ls(x) (x << 1)
#define rs(x) (x << 1 | 1)
void pushUp(int i) {
t[i].sum = t[ls(i)].sum + t[rs(i)].sum;
t[i].his = t[ls(i)].his + t[rs(i)].his;
}
void pushR(int i, int l, int r) {
t[i].sum = r - l + 1 - t[i].sum;
swap(t[i].atag1, t[i].atag2);
t[i].rtag ^= 1;
}
void pushA1(int i, int atag1) {
t[i].his += t[i].sum * atag1;
t[i].atag1 += atag1;
}
void pushA2(int i, int l, int r, int atag2) {
t[i].his += (r - l + 1 - t[i].sum) * atag2;
t[i].atag2 += atag2;
}
void pushDown(int i, int l, int r) {
int mid = (l + r) >> 1;
if (t[i].rtag) pushR(ls(i), l, mid), pushR(rs(i), mid + 1, r), t[i].rtag = 0;
if (t[i].atag1) pushA1(ls(i), t[i].atag1), pushA1(rs(i), t[i].atag1), t[i].atag1 = 0;
if (t[i].atag2) pushA2(ls(i), l, mid, t[i].atag2), pushA2(rs(i), mid + 1, r, t[i].atag2), t[i].atag2 = 0;
}
void modify(int i, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) return pushR(i, l, r);
int mid = (l + r) >> 1;
pushDown(i, l, r);
if (ql <= mid) modify(ls(i), l, mid, ql, qr);
if (qr > mid) modify(rs(i), mid + 1, r, ql, qr);
pushUp(i);
}
ll query(int i, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) return t[i].his;
int mid = (l + r) >> 1; ll res = 0;
pushDown(i, l, r);
if (ql <= mid) res += query(ls(i), l, mid, ql, qr);
if (qr > mid) res += query(rs(i), mid + 1, r, ql, qr);
return res;
}
#undef ls
#undef rs
int main() {
n = read();
for (int i = 1; i <= n; i++)
a[i] = read(), pre[i] = pos[a[i]], pos[a[i]] = i;
m = read();
for (int i = 1; i <= m; i++)
q[i].l = read(), q[i].r = read(), q[i].id = i;
sort(q + 1, q + m + 1, [](const Query &lhs, const Query &rhs) {
return lhs.r < rhs.r;
});
for (int i = 1, j = 1; i <= m; i++) {
while (j <= q[i].r) {
modify(1, 1, n, pre[j] + 1, j);
pushA1(1, 1);
j++;
}
ans[q[i].id] = query(1, 1, n, q[i].l, q[i].r);
}
for (int i = 1; i <= m; i++)
printf("%lld\n", ans[i]);
return 0;
}
本文来自博客园,作者:registerGen,转载请注明原文链接:https://www.cnblogs.com/registergen/p/cfgym103069g_solution.html

浙公网安备 33010602011771号