简单说一下莫队算法的复杂度,莫队算法其实是在区间的进退处理上进行了一个优化,大大降低复杂度,首先是区间的分块处理,将数据分为 n√ 个块,考虑左边界的移动情况,由于每个块中每个询问左边界最多移动 n√ 步,所以左边界的复杂度为 mn√ ,再考虑右边界的移动情况,由于块中右边界保持升序,所以一个块中右边界的移动复杂度为 n√ ,考虑块与块之间的移动情况,最多为n步,所以右边界移动的复杂度为 nn√ ,再加上统计color的复杂度为 O1 ,所以整体复杂度为 (m+n)n√
#include<cstring>
#include<string>
#include<iostream>
#include<queue>
#include<cstdio>
#include<algorithm>
#include<map>
#include<cstdlib>
#include<cmath>
#include<vector>
//#pragma comment(linker, "/STACK:1024000000,1024000000");
using namespace std;
#define INF 0x3f3f3f3f
#define maxn 100005
struct node
{
int l, r;
int id;
} q[maxn];
int vis[maxn];
int block[maxn];
int col[maxn];
int ans1[maxn],ans2[maxn];
int a,b;
bool cmp(node A,node B)
{
if(block[A.l]==block[B.l]) return A.r<B.r;
return block[A.l]<block[B.l];
}
void update(int add,int pos)
{
if(add==1) a+=vis[pos],vis[pos]++;
else a-=vis[pos]-1,vis[pos]--;
}
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(vis,0,sizeof vis);
int bk=ceil(sqrt(n*1.0));
for(int i=1; i<=n; i++)
{
scanf("%d",&col[i]);
block[i]=i/bk;
}
block[n+1]=block[n]+1;
for(int i=0; i<m; i++)
{
scanf("%d%d",&q[i].l,&q[i].r);
q[i].id=i;
}
sort(q,q+m,cmp);
int l=0,r=1;
a=0,b=0;
for(int i=0; i<m; i++)
{
if(q[i].r-q[i].l==0)
{
ans1[q[i].id]=0;
ans2[q[i].id]=1;
continue;
}
for(;r<=q[i].r;r++) update(1,col[r]);
for(;r-1>q[i].r;r--) update(-1,col[r-1]);
for(;l+1<q[i].l;l++) update(-1,col[l+1]);
for(;l>=q[i].l;l--) update(1,col[l]);
ans1[q[i].id]=a;
b=q[i].r-q[i].l+1;
if(b%2==0) ans2[q[i].id]=b/2*(b-1);
else ans2[q[i].id]=(b-1)/2*b;
}
for(int i=0; i<m; i++)
{
int temp=__gcd(ans1[i],ans2[i]);
ans1[i]/=temp;
ans2[i]/=temp;
if(ans1[i]==0) ans2[i]=1;
printf("%d/%d\n",ans1[i],ans2[i]);
}
}
return 0;
}