补题链接
看网上好像不怎么找不到代码,发一份出来
#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
using i128 = __int128;
constexpr int maxn = 1e5+10,k = 316;
int n,m,a[maxn],f[maxn];
vector<int> pos[maxn];
i64 pre[320][maxn];
signed main(){
ios::sync_with_stdio(0);cin.tie(0);
cin>>n>>m;
for(int i = 1;i<=n;++i){
cin>>a[i];
pos[a[i]].emplace_back(i);
}
for(int i = 1;i<=n;++i){
if(pos[i].size()>k){
f[0]++;
f[i] = f[0];
for(int j = 1;j<=n;++j){
pre[f[i]][j] = pre[f[i]][j-1]+(a[j]==i);
}
for(int j = 1;j<=n;++j){
int lst_p =0;
for(int p:pos[j]){
pre[f[i]][p] = pre[f[i]][p]+pre[f[i]][lst_p];//真正有用位置的前缀和,二次累加
lst_p = p;
}
}
}
}
for(int i = 1;i<=n;++i) pos[i].emplace_back(n+10);
for(int qry=1;qry<=m;++qry){
int l,r,p,q;//题目保证p<q
cin>>l>>r>>p>>q;
if(pos[p].size()<=k+1&&pos[q].size()<=k+1){
int pl=0,np=0,nq=0,nn=0;//np,nq记录p,q的指针指到哪里了
i64 ans =0;
while(np<pos[p].size()||nq<pos[q].size()){
if(np==pos[p].size()){
pl = pos[q][nq];
nq++;
}else if(nq==pos[q].size()){
pl = pos[p][np];
np++;
}else if(pos[q][nq]<pos[p][np]){
pl = pos[q][nq];
++nq;
}else{
pl = pos[p][np];
np++;
}
if(l<=pl&&pl<=r){
if(a[pl]==q) ++nn;
else ans+=nn;//累加每个q的贡献
}
}
cout<<ans<<"\n";
}else{
if(pos[p].size()<pos[q].size()) swap(p,q);//可能导致求成顺序对
i64 ans =0 ;
int pl = lower_bound(pos[p].begin(),pos[p].end(),l)-pos[p].begin();
int pr = upper_bound(pos[p].begin(),pos[p].end(),r)-pos[p].begin();
pr--;pl--;//相当于[l-1,r]
int ql = lower_bound(pos[q].begin(),pos[q].end(),l)-pos[q].begin();
int qr = upper_bound(pos[q].begin(),pos[q].end(),r)-pos[q].begin();
qr--;ql--;
i64 nn = pr-pl;
i64 nnq = qr-ql;
if(nn>0&&nnq>0){
if(qr>=0) qr = pos[q][qr];
else qr =0;
if(ql>=0) ql = pos[q][ql];
else ql=0;
if(ql<=qr) ans+=(pre[f[p]][qr]-pre[f[p]][ql])-nnq*(pl+1);
if(p<q) ans = nn*nnq-ans;
}
cout<<ans<<"\n";
}
}
return 0;
}