今天总算撸懂了莫队
贴一个模板题代码 小Z的袜子
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int max_n=500005;
int n,m,size;
int hose[max_n],pos[max_n];
long long tot[max_n];
class Query
{
public:
int l;int r;int id;long long a,b;
}q[max_n];
bool cmp(Query a,Query b)
{
if(pos[a.l]==pos[b.l]) return a.r<b.r;
else return pos[a.l]<pos[b.l];
}
int L=1,R=0;
long long ans=0;
void change(int val,int cl)
{
ans-=tot[cl]*tot[cl];
tot[cl]+=val;
ans+=tot[cl]*tot[cl];
}
long long gcd(long long a,long long b) { return b==0?a:gcd(b,a%b); }
void work()
{
for(register int i=1;i<=m;i++)
{
if(q[i].l==q[i].r) q[i].a=0,q[i].b=1;
else
{
while(L<q[i].l) change(-1,hose[L]),L++;
while(L>q[i].l) L--,change(1,hose[L]);
while(R<q[i].r) R++,change(1,hose[R]);
while(R>q[i].r) change(-1,hose[R]),R--;
q[i].a=ans-(q[i].r-q[i].l+1);q[i].b=(long long)(q[i].r-q[i].l+1)*(q[i].r-q[i].l);
long long k=gcd(q[i].a,q[i].b);
q[i].a/=k;q[i].b/=k;
}
}
}
bool outcmp (Query a ,Query b) { return a.id<b.id;}
void output()
{
sort(q+1,q+1+m,outcmp);
for(register int i=1;i<=m;i++)
printf("%lld/%lld\n",q[i].a,q[i].b);
}
int main()
{
scanf("%d%d",&n,&m);
for(register int i=1;i<=n;i++)
scanf("%d",&hose[i]);
size=(int)sqrt(n+0.5);
for(register int i=0;i<=n;i++)
pos[i]=i/size;
for(register int i=1;i<=m;i++)
scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
sort(q+1,q+1+m,cmp);
work();
output();
return 0;
}
如果当前已知区间的左端点小于询问区间的左端点,则需要将当前已知区间的左端点向右移。每次右移之前都需要先减去当前点对答案的影响。
如果当前已知区间的左端点大于询问区间的左端点,则需要将当前已知区间的左端点向左移。每次左移之后都需要再加上当前点对答案的影响。
右区间同理
while(L<Q.L) Modify(L,-1),L++;
while(L>Q.L) L--,Modify(L,1);
while(R<Q.R) R++,Modify(R,1);
while(R>Q.R) Modify(R,-1),R--;
在答案中减去当前状态未被修改时对答案的贡献,进行修改操作后,再在答案中加上该状态被修改后对答案的新计算出的贡献。