P10149 [Ynoi1999] XM66F 做题记录

小清新题。

题目描述

给定序列 $a_1,\dots,a_n$ ,$m$ 次询问,每次询问给出 $l,r$ ,问有多少组 $(i,j,k)$ 满足 $l\le i<j<k\le r,\;a_i=a_k>a_j$ 。

思路

记 $w_x$ 为 $\sum_{i=1}^{x}[a_i<a_x]$,即 $1\sim x$ 中小于 $a_x$ 的数的个数。从左往右依次将数加入值域树状数组即可在 $O(n\log n)$ 的时间复杂度内计算 $w$。

不难发现,需要求的答案为 $\sum_{l\le i\lt j\le r,a_i=a_j}w_j-w_i$。考虑使用莫队计算,则需快速移动左右端点。记 $t_i$ 为当前区间内值 $i$ 的出现次数,$f_i$ 为值 $i$ 出现位置对应的 $w$ 的和,若加入一个数 $a_i$,其对答案的贡献为 $|t_{a_i}w_i-f_{a_i}|$。删除数的时候同理。这样,我们做到了 $O(1)$ 移动左右端点,时间复杂度为 $O(n\sqrt{n})$。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
constexpr int N=5e5+5,B=710;using ll=long long;
namespace BIT
{
int c[N],n;
inline void init(int _n){n=_n;}
inline int lowbit(int x){return x&(-x);}
inline void update(int x){while(x<=n)c[x]++,x+=lowbit(x);}
inline int query(int x){int res=0;while(x)res+=c[x],x-=lowbit(x);return res;}
}
int a[N],w[N],bel[N],t[N];ll ans[N],ts[N],now=0;struct Q{int l,r,id;}q[N];
inline void addr(int x){now+=1ll*t[a[x]]*w[x]-ts[a[x]];t[a[x]]++;ts[a[x]]+=w[x];}
inline void addl(int x){now+=ts[a[x]]-1ll*t[a[x]]*w[x];t[a[x]]++;ts[a[x]]+=w[x];}
inline void delr(int x){t[a[x]]--;ts[a[x]]-=w[x];now-=1ll*t[a[x]]*w[x]-ts[a[x]];}
inline void dell(int x){t[a[x]]--;ts[a[x]]-=w[x];now-=ts[a[x]]-1ll*t[a[x]]*w[x];}
inline void work()
{
using namespace IO;
int n,m,l=1,r=0;qread(n),qread(m);BIT::init(n);
for(int i=1;i<=n;i++) qread(a[i]),w[i]=BIT::query(a[i]-1),BIT::update(a[i]);
for(int i=1;i<=n;i++) bel[i]=(i-1)/B+1;
for(int i=1;i<=m;i++) qread(q[i].l),qread(q[i].r),q[i].id=i;
sort(q+1,q+m+1,[](const Q&x,const Q&y){return bel[x.l]<bel[y.l]||(bel[x.l]==bel[y.l]&&((bel[x.l]&1)?(x.r<y.r):(x.r>y.r)));});
for(int i=1;i<=m;i++)
{
while(r<q[i].r) addr(++r);
while(l>q[i].l) addl(--l);
while(r>q[i].r) delr(r--);
while(l<q[i].l) dell(l++);
ans[q[i].id]=now;
}
for(int i=1;i<=m;i++) qwrite(ans[i]),pc('\n');
}

P10149 [Ynoi1999] XM66F 做题记录
https://www.llingy.top/posts/2279033634/
作者
llingy
发布于
2024年2月19日
许可协议