#线段树#洛谷 9990 [Ynoi Easy Round 2023] TEST_90
题目
给定一个长度 \(n(n\leq 10^6)\) 的序列 \(a_1,…,a_n\)。共有 \(m\) 次询问,每次询问给定 \(l,r\),
求区间 \([l,r]\) 中有多少子区间 \([i,j]\) 满足 \(l\leq i\leq j\leq r\),且在区间 \([i,j]\) 内出现过的数的个数为奇数。
分析
将询问按右端点排序离线,假如 \(a_r\) 上一次出现的位置为 \(a_{pre}\),那么会对 \([pre+1,r]\) 的区间出现数个数的奇偶性互换。
然后相当于将数组整体加到答案数组里,每次查询 \(s_{l\sim r}\)。首先解决历史区间和的问题,
相当于有两个数组 \(a_0,a_1\),其中一个填 \(1\) 表示 \([i,r]\) 出现数个数为偶数,另一个表示当前出现数个数为奇数。
那么每次给答案 \(b_i\) 加上 \(a_{1,i}\),查询 \(b_i\) 的和。其实就是在线段树上分别维护 \(a_0\) 和 \(a_1\) 的和。
区间加其实是加上对应 \(a\) 的和,奇偶性互换采用动态开点线段树,交换对应区间就可以了。
代码
#include <iostream>
#include <algorithm>
using namespace std;
const int N=1000011; struct node{int y,next;}e[N];
typedef long long lll; lll w[N<<2],c[N<<2],ans[N];
int ls[N<<2],rs[N<<2],lazy[N<<2],rt[2],cnt,Q,n,a[N],pre[N],as[N];
void build(int &rt,int l,int r){
rt=++cnt,c[rt]=Q?0:r-l+1;
if (l==r) return;
int mid=(l+r)>>1;
build(ls[rt],l,mid);
build(rs[rt],mid+1,r);
}
void update(int &fi,int &se,int l,int r,int x,int y){
if (l==x&&r==y){
swap(fi,se);
return;
}
int mid=(l+r)>>1;
if (lazy[fi]){
w[ls[fi]]+=lazy[fi]*c[ls[fi]],lazy[ls[fi]]+=lazy[fi];
w[rs[fi]]+=lazy[fi]*c[rs[fi]],lazy[rs[fi]]+=lazy[fi];
lazy[fi]=0;
}
if (lazy[se]){
w[ls[se]]+=lazy[se]*c[ls[se]],lazy[ls[se]]+=lazy[se];
w[rs[se]]+=lazy[se]*c[rs[se]],lazy[rs[se]]+=lazy[se];
lazy[se]=0;
}
if (y<=mid) update(ls[fi],ls[se],l,mid,x,y);
else if (x>mid) update(rs[fi],rs[se],mid+1,r,x,y);
else update(ls[fi],ls[se],l,mid,x,mid),update(rs[fi],rs[se],mid+1,r,mid+1,y);
w[fi]=w[ls[fi]]+w[rs[fi]],c[fi]=c[ls[fi]]+c[rs[fi]];
w[se]=w[ls[se]]+w[rs[se]],c[se]=c[ls[se]]+c[rs[se]];
}
void update(int k,int l,int r,int x,int y){
if (l==x&&r==y){
++lazy[k],w[k]+=c[k];
return;
}
int mid=(l+r)>>1;
if (lazy[k]){
w[ls[k]]+=lazy[k]*c[ls[k]],lazy[ls[k]]+=lazy[k];
w[rs[k]]+=lazy[k]*c[rs[k]],lazy[rs[k]]+=lazy[k];
lazy[k]=0;
}
if (y<=mid) update(ls[k],l,mid,x,y);
else if (x>mid) update(rs[k],mid+1,r,x,y);
else update(ls[k],l,mid,x,mid),update(rs[k],mid+1,r,mid+1,y);
w[k]=w[ls[k]]+w[rs[k]],c[k]=c[ls[k]]+c[rs[k]];
}
lll query(int k,int l,int r,int x,int y){
if (l==x&&r==y) return w[k];
int mid=(l+r)>>1;
if (lazy[k]){
w[ls[k]]+=lazy[k]*c[ls[k]],lazy[ls[k]]+=lazy[k];
w[rs[k]]+=lazy[k]*c[rs[k]],lazy[rs[k]]+=lazy[k];
lazy[k]=0;
}
if (y<=mid) return query(ls[k],l,mid,x,y);
else if (x>mid) return query(rs[k],mid+1,r,x,y);
else return query(ls[k],l,mid,x,mid)+query(rs[k],mid+1,r,mid+1,y);
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
for (int i=1;i<=n;++i) cin>>a[i];
build(rt[0],1,n),Q=1,build(rt[1],1,n);
cin>>Q;
for (int i=1;i<=Q;++i){
int l,r; cin>>l>>r;
e[i]=(node){l,as[r]},as[r]=i;
}
for (int i=1;i<=n;++i){
update(rt[0],rt[1],1,n,pre[a[i]]+1,i),update(rt[1],1,n,1,i),pre[a[i]]=i;
for (int j=as[i];j;j=e[j].next) ans[j]=query(rt[0],1,n,e[j].y,i)+query(rt[1],1,n,e[j].y,i);
}
for (int i=1;i<=Q;++i) cout<<ans[i]<<'\n';
return 0;
}

浙公网安备 33010602011771号