做题记录整理莫队1 P1494 [国家集训队] 小 Z 的袜子(2022/9/15)

P1494 [国家集训队] 小 Z 的袜子

莫队模板

莫队能做的题基本都是这个模板,一般只变动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;
}
posted @ 2022-09-15 20:11  yyx525jia  阅读(26)  评论(0)    收藏  举报