小Z的袜子 莫队入门

https://www.lydsy.com/JudgeOnline/problem.php?id=2038

 思路:离线做法,将所有的询问先存下来,然后将区间分为sqrt(n)份,然后按照区间给询问排个序,按照询问区间左端点所在的块为第一排序顺序,询问区间右端点为第二排序标准。

之后就是通过利用两个指针在询问区间来回移动,前提是每改变一个位置可以O(1)的得到它增加或减少这个元素所对应的值,每变化一个元素就要改变它所对应的答案值。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1e5+10;
int color[maxn];
struct note
{
    ll id,l,r,fz,fm;
} ans[maxn];
int block[maxn];
int sum[maxn];
int cmp1(note a,note b)
{
    if(block[a.l]<block[b.l]) return 1;
    if(block[a.l]>block[b.l]) return 0;
    return a.r<b.r;
}
ll cmp2(note a,note b)
{
    return a.id<b.id;
}
int gcd(ll a,ll b)
{
    return a%b==0?b:gcd(b,a%b);
}

int main()
{
    int n,q;
    scanf("%d%d",&n,&q);
    for(int i=1; i<=n; i++)
        scanf("%d",&color[i]);
    for(int i=1; i<=q; i++)
    {
        scanf("%d%d",&ans[i].l,&ans[i].r);
        ans[i].id=i;
    }
    block[0]=sqrt(n);
    for(int i=1; i<=n; i++)
        block[i]=(i-1)*block[0]+1;
    sort(ans+1,ans+q+1,cmp1);
    int last_l,last_r;
    last_l=1;
    last_r=0;
    ll temp=0;
    for(int i=1; i<=q; i++)
    {
        ans[i].fm=(ans[i].r-ans[i].l+1)*(ans[i].r-ans[i].l);
        if(last_l<ans[i].l)
        {
            for(int j=last_l; j<ans[i].l; j++)
            {
                temp=temp-(sum[color[j]]*2-1);
                sum[color[j]]--;
            }
        }
        if(last_l>ans[i].l)
        {
            for(int j=last_l-1; j>=ans[i].l; j--)
            {
                temp=temp+(sum[color[j]]*2+1);
                sum[color[j]]++;
            }
        }
        if(last_r<ans[i].r)
        {
            for(int j=last_r+1; j<=ans[i].r; j++)
            {
                temp=temp+(sum[color[j]]*2+1);
                sum[color[j]]++;
            }
        }
        if(last_r>ans[i].r)
        {
            for(int j=last_r; j>ans[i].r; j--)
            {
                temp=temp-(sum[color[j]]*2-1);
                sum[color[j]]--;
            }
        }
        ans[i].fz=temp-(ans[i].r-ans[i].l+1);
        last_l=ans[i].l;
        last_r=ans[i].r;
    }
    sort(ans+1,ans+1+q,cmp2);
    for(int i=1; i<=q; i++)
    {
//        printf("%lld %lld
",ans[i].fz,ans[i].fm);
        if(ans[i].fz==0)
        {
            printf("0/1
");continue;
        }
        ll t=gcd(ans[i].fz,ans[i].fm);
        printf("%lld/%lld
",ans[i].fz/t,ans[i].fm/t);
    }
}
原文地址:https://www.cnblogs.com/dongdong25800/p/11375610.html