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号
浙公网安备 33010602011771号