莫队算法
E. Easy String Problem
题意:好懒的人啊,自己看题~~~
题解:这道题正解是莫队,那么我们怎么可以想到莫队的呢?有以下几个特征点可以指引我们想到莫队,首先是数据规模\(1e5\),这个\(1e5\)其实对应的算法是不多的,比如莫队,分块,块状链表等等,第二是区间询问是莫队的典型特征。其实根据数据规模能得到很多信息的,毕竟出题人也不傻~~~。
我们由此可以得到一个初步判断,他就是莫队,基于这个去思考这道题的性质将会容易很多。 看到这不妨停下来自己想想,莫队需要哪些性质,而我们怎么挖掘与其相关的性质?
不知道聪明的你想到了没有,其实很简单,观察12321,我们假设询问区间是3 3,我们使用正难则反的思路,左边的坐标有三个选择,右边同样是三个,所以可以得到\(3 * 3 = 9\)这个答案,我们考虑如何去重,可以发现,删去2 3和3 4一样,1 3和3 5一样,发现好像与区间两旁的重复部分有关系,再比如11312,同样询问3 3,答案同样是 $ 9 - 2 $,我们可以发现和两边重复数字的个数乘积有关系,没错一个询问区间答案就是全部取法减去两边重复数字个数的乘积。我们通过莫队可以轻松维护~~~
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<(b);i++)
#define ll long long
const int N = 1e5+5;
int a[N];
int len;
ll ans[N];
int n,m;
struct Query{
int id,l,r;
}q[N];
int get(int x){
return x/len;
}
int cntr[N];
int cntl[N];
void addr(int x,ll& quan){
cntr[x]--;
quan -= cntl[x];
}
void delr(int x,ll& quan){
cntr[x]++;
quan += cntl[x];
}
void addl(int x,ll& quan){
cntl[x]--;
quan -= cntr[x];
}
void dell(int x,ll& quan){
cntl[x]++;
quan += cntr[x];
}
int main(){
cin >> n;
len = max(1,(int)sqrt(n));
for(int i=1;i<=n;i++)cin >> a[i];
cin >> m;
rep(i,0,m){
int l,r;cin >> l >> r;
q[i] = {i,l,r};
}
sort(q,q+m,[&](Query a,Query b){
int i = get(a.l), j = get(b.l);
if(i!=j)return i < j;
return a.r < b.r;
});
int L = 1, R = n;
ll quan = 0;
rep(i,0,m){
int l = q[i].l,r = q[i].r,id = q[i].id;
while(R < r)addr(a[++R],quan);
while(R > r)delr(a[R--],quan);
while(L > l)addl(a[--L],quan);
while(L < l)dell(a[L++],quan);
//cout << quan << " " << l << " " << r << endl;
ans[id] = 1ll * l * (n + 1 - r) - quan;
}
rep(i,0,m){
printf("%lld\n",ans[i]);
}
}
浙公网安备 33010602011771号