BZOJ2038【莫队算法】

THE FIRST 莫队算法。

/**************************************************************
    Problem: 2038
    User: keyboarder_zsq
    Language: C++
    Result: Accepted
    Time:1644 ms
    Memory:2988 kb
****************************************************************/
 
//#include <bits/stdc++.h>
#include<cstdio>
#include<math.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
 
const int N=5e4+10;
struct asd{
    LL a,b;
    int left,right;
    int id;
};
int n,m,col[N],pos[N];
asd q[N];
bool cmp(asd x,asd y)
{
    if(pos[x.left]==pos[y.left]) return x.right<y.right;
    return x.left<y.left;
}
bool cmp_id(asd x,asd y)
{
    return x.id<y.id;
}
 
LL ans,num[N];
void update(int p,int add)
{
    ans-=num[col[p]]*num[col[p]];
    num[col[p]]+=add;
    ans+=num[col[p]]*num[col[p]];
}
 
void solve()
{
    memset(num,0,sizeof(num));
    ans=0;
    for(int i=0,L=1,R=0;i<m;i++)
    {
        while(R<q[i].right)
        {
            update(R+1,1);
            R++;
        }
        while(R>q[i].right)
        {
            update(R,-1);
            R--;
        }
        while(L<q[i].left)
        {
            update(L,-1);
            L++;
        }
        while(L>q[i].left)
        {
            update(L-1,1);
            L--;
        }
        if(q[i].left==q[i].right)
        {
            q[i].a=0;q[i].b=1;
            continue;
        }
        q[i].a=ans-(q[i].right-q[i].left+1);
        q[i].b=(LL)(q[i].right-q[i].left+1)*(q[i].right-q[i].left);
        LL gcd=__gcd(q[i].a,q[i].b);
        q[i].a/=gcd;
        q[i].b/=gcd;
    }
}
 
int main()
{
    scanf("%d%d",&n,&m);
    int block=(int)sqrt(n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&col[i]);
        pos[i]=(i-1)/block+1;
    }
    for(int i=0;i<m;i++)
    {
        scanf("%d%d",&q[i].left,&q[i].right);
        q[i].id=i;
    }
    sort(q,q+m,cmp);
    solve();
    sort(q,q+m,cmp_id);
    for(int i=0;i<m;i++)
        printf("%lld/%lld\n",q[i].a,q[i].b);
    return 0;
}
/*
6 4
1 2 3 3 3 2
2 6
1 3
3 5
1 6
*/


转载于:https://www.cnblogs.com/keyboarder-zsq/p/6777418.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值