做题记录整理莫队1 P1494 [国家集训队] 小 Z 的袜子(2022/9/15)
莫队模板
莫队能做的题基本都是这个模板,一般只变动jia()函数中的东西,所以莫队其实不是一个很难的算法(仅仅指普通莫队)
#include<bits/stdc++.h>
#define for1(i,a,b) for(int i=a;i<=b;i++)
#define ll long long
using namespace std;
struct node{//询问
int l;
int r;
int id;
ll fz,fm;
}a[500005];
int n,m,c[500005],ji[500005];
int pos[50005];//记录每个数据属于哪个块
int l,r;
ll ans;//记录当前答案
ll gcd(ll x,ll y)
{
return y==0?x:gcd(y,x%y);
}
bool cmp(node x,node y)
{
if(pos[x.l]==pos[y.l]) return x.r<y.r;
return x.l<y.l;
}
bool cmp2(node x,node y)
{
return x.id<y.id;
}
void jia(int x,int y)//需要添加、删除的元素下标,区间长度的变化
{
ans-=ji[c[x]]*ji[c[x]];//减去原来的区间和
ji[c[x]]+=y;//添加、删除元素
ans+=ji[c[x]]*ji[c[x]];//更新
}
void cl() //处理询问
{
for(int l=1,r=0,i=1;i<=m;i++)
{
while(r<a[i].r)
{
jia(r+1,1);
r++;
}
while(r>a[i].r)
{
jia(r,-1);
r--;
}
while(l<a[i].l)
{
jia(l,-1);
l++;
}
while(l>a[i].l)
{
jia(l-1,1);
l--;
}
if(a[i].l==a[i].r)//特判
{
a[i].fz=0;
a[i].fm=1;
continue;
}
a[i].fz=ans-(a[i].r-a[i].l+1);//平方和减区间长度
a[i].fm=(a[i].r-a[i].l+1)*1ll*(a[i].r-a[i].l);
ll g=gcd(a[i].fz,a[i].fm);//约分
a[i].fz/=g;
a[i].fm/=g;
}
}
int main()
{
scanf("%d%d",&n,&m);
for1(i,1,n) scanf("%d",&c[i]);
int shuliang=sqrt(n);//分块的数量
for1(i,1,n)
pos[i]=(i-1)/shuliang+1;
for1(i,1,m)
{
scanf("%d%d",&a[i].l,&a[i].r);
a[i].id=i;
}
sort(a+1,a+m+1,cmp);//排序
cl();//处理
sort(a+1,a+m+1,cmp2);//恢复原来的顺序
for1(i,1,m)
printf("%lld/%lld\n",a[i].fz,a[i].fm);
return 0;
}

浙公网安备 33010602011771号