给定序列 a 1 , a 2 , … , a n a_1, a_2, \dots, a_n a1,a2,…,an以及 m m m个询问。对于每个询问 ( l , r ) (l, r) (l,r)回答区间 [ l , r ] [l, r] [l,r]中满足不同数字个数为奇数的子区间个数。
首先将所有询问离线,然后考虑对同一 L L L回答所有 R R R的答案。
我们可以通过维护所有以 L L L为起点,以 i ( 1 ≤ i ≤ n ) i(1 \leq i \leq n) i(1≤i≤n)为终点的区间奇偶结果序列。那么考虑区间如何扩展:
设 p r e [ a [ i ] ] pre[a[i]] pre[a[i]]表示上个 a [ i ] a[i] a[i]的位置。
对于 [ L + 1 , n ] → [ L , n ] [L+ 1,n] \rightarrow [L, n] [L+1,n]→[L,n],如果存在 i i i使得 p r e [ a [ i ] ] = L pre[a[i]] = L pre[a[i]]=L,则 [ i , n ] [i, n] [i,n]所有区间所有的右端点和 L L L组成的区间都不会发生奇偶性反转,而 [ L , i ] [L, i] [L,i]会反转。
扩展完区间后,我们可以直接查询区间和,即为最终答案。
那么我们需要使用线段树维护
- 区间和以及奇偶区间和
- 奇偶性统计
- 更新标记/懒标记
- 反转标记
注意进行反转操作的时候,需要交换 l a z y lazy lazy标记。
Code#include
#pragma gcc optimize(2)
#define SEGRG 1, 1, n
#define int long long
#define endl '\n'
using namespace std;
const int N = 1e6 + 10;
int a[N], pre[N], lst[N], ans[N];
namespace SegmentTree{
#define ls rt > r;
q[l].emplace_back(query{.r = r, .id = i});
}
SegmentTree::build(SEGRG);
for(int i = n; i >= 1; i--){
SegmentTree::update(SEGRG, i, n);
for(int j = 0; j
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?