莫队模板题 bzoj2038

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<set>
#include<queue>
#include<vector>
#include<string>
#include<cstring>
#include<bitset>
#include<map>
#define mp make_pair
#define pb push_back
#define ll long long
using namespace std;
const int maxn=5e5+7;
const int maxs=3e5+5;
ll gcd(ll a,ll b)
{
	return b==0?a:gcd(b,a%b);
}
ll sqr(ll x)
{
	return x*x;
}
int n,m,k;
int a[maxn];
int val[maxn],pos[maxn];
int block;
ll ans;
struct node
{
	int l,r,id;
	ll a,b;
}nod[maxn];
bool cmp1(node a,node b){if(pos[a.l]==pos[b.l])return a.r<b.r;return a.l<b.l; }
bool cmp2(node a,node b){return a.id<b.id;}
void update(int x,int vs)
{
	ans-=sqr(val[a[x]]);
	val[a[x]]+=vs;
	ans+=sqr(val[a[x]]);
}
int main()
{
	scanf("%d%d",&n,&m);
	ans=0;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
	}
	for(int i=0;i<m;i++)
	{
		scanf("%d%d",&nod[i].l,&nod[i].r);
		nod[i].id=i;
	}
	block=sqrt(n);
	for(int i=1;i<=n;i++)
    {
        pos[i]=(i-1)/block+1;
    }
	sort(nod,nod+m,cmp1);
	int l=1,r=1;
	update(r,1);
	for(int i=0;i<m;i++)
	{
		while(r<nod[i].r)
        {
            update(r+1,1);
            r++;
        }
        while(r>nod[i].r)
        {
            update(r,-1);
            r--;
        }
        while(l<nod[i].l)
		{
			update(l,-1);
			l++;
		}
		while(l>nod[i].l)
		{
			update(l-1,1);
			l--;
		}
		if(nod[i].l==nod[i].r)
		{
			nod[i].a=0,nod[i].b=1;
			continue;
		}
		nod[i].a=ans-(nod[i].r-nod[i].l+1);
		nod[i].b=1ll*(nod[i].r-nod[i].l)*(nod[i].r-nod[i].l+1);
		ll fs=gcd(nod[i].a,nod[i].b);
		nod[i].a/=fs;
		nod[i].b/=fs;
	}
	sort(nod,nod+m,cmp2);
	for(int i=0;i<m;i++)printf("%lld/%lld\n",nod[i].a,nod[i].b);
}

常规orz&&感谢 hzwer的代码,就存一下了,确实是很暴力的算法,很好理解但是有些小细节一定要注意,那四段先后顺序无影响,但必须为1~n(这个意会就好),但是l和r如果初始都为1那么要把1-1这个区间先加进去。就这样

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值