P10149 [Ynoi1999] XM66F题解
题解
首先,问题是静态的区间查询问题,一眼莫队。那么我们就需要考虑所需要维护的内容在区间扩增或者缩减时的变化如何快速维护。我们可以先写出对于区间
记作形式 1。或者:
记作形式 2,上述括号均为艾弗森括号。
接下来我们分别考虑
注意到后面的求和式实际上是一个二维偏序,我们按照前缀和的思路记:
显然可以用树状数组做到
这下就很显然了,我们动态维护两个桶
对于左端点左移,我们运用形式 2,和刚才一样的方法,增量可以写成:
形式一点没变,但是系数变为原来的相反数,这不影响统计,我们仍然可以按照刚才的维护方法进行左端点左移,不过我们可能要特殊判断一下增量的系数。
但也不必,显然区间扩增后,增量一定是非负数,那么我们可以认为左端点左移的增量式子是其相反数的绝对值,而右端点右移的增量式子是其本身的绝对值,这样形式和系数都统一了,不需要特判,代码实现比较工整。
由于可以
AC code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e5+10;
int n,m,a[N],l,r,cnt[N],s1[N],s2[N];
int B,ans[N],now;
struct Query {
int l,r,id,bel;
}q[N];
struct BST {
int c[N];
int lowbit(int x) {
return x&-x;
}
void update(int x,int y) {
for(;x<=n;x+=lowbit(x)) c[x]+=y;
}
int sum(int x) {
int ans=0;
while(x>0) {
ans+=c[x];
x-=lowbit(x);
}
return ans;
}
}T;
bool cmp(Query x,Query y) {
if(x.bel!=y.bel) return x.bel<y.bel;
if(x.bel&1) return x.r<y.r;
else return x.r>y.r;
}
void add(int i) {
now+=abs(cnt[i]*s1[a[i]]-s2[a[i]]);
s1[a[i]]++;
s2[a[i]]+=cnt[i];
}
void del(int i) {
s1[a[i]]--;
s2[a[i]]-=cnt[i];
now-=abs(cnt[i]*s1[a[i]]-s2[a[i]]);
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
B=(int)(n*1.0/sqrt(m));
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) {
T.update(a[i],1);
cnt[i]=T.sum(a[i]-1);
}
for(int i=1;i<=m;i++) {
cin>>l>>r;
q[i]={l,r,i,(l-1)/B+1};
}
sort(q+1,q+m+1,cmp);
l=1,r=1;
s1[a[1]]++;
s2[a[1]]+=cnt[1];
for(int i=1;i<=m;i++) {
while(l>q[i].l) add(--l);
while(r<q[i].r) add(++r);
while(l<q[i].l) del(l++);
while(r>q[i].r) del(r--);
ans[q[i].id]=now;
}
for(int i=1;i<=m;i++) cout<<ans[i]<<endl;
return 0;
}
本文作者:2021hych
本文链接:https://www.cnblogs.com/2021hych/p/18017402
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步