【Luogu】P2709小B的询问(莫队算法)

  题目链接

  md,1A率等于0.

  烦死。

  终于搞到一道莫队了qwq。

  先对区间分块再按照块编号为第一关键字,右端点为第二关键字排序,然后每次端点移动1乱搞。

  然后……就wa了。

  然后有很多细节需要注意qwq。比如这是个离线算法,在线输出个鬼

  当然更有可能是我太菜了

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cctype>
#include<cmath>
using namespace std;
inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

long long nu[51000];
long long d[1000010];
int s[1000100];
int la[1000100];
int ans[1000100];
long long sum;

struct Que{
    long long x,y;
    int id;
    bool operator <(const Que a){
        if(s[x]!=s[a.x])    return s[x]<s[a.x];
        else return y<a.y;
    }
}que[1000010];

int main(){
    int n=read(),m=read(),q=read();
    int b=sqrt(n);
    for(int i=1;i<=n;++i){
        d[i]=read();
        s[i]=(i-1)/b+1;
    }
    for(int i=1;i<=m;++i)    que[i]=(Que){read(),read(),i};
    sort(que+1,que+m+1);
    for(int i=m;i;--i)    la[s[que[i].x]]=i;
    long long sum=1;    nu[0]=1;
    int l=0,r=0;
    for(int j=1;j<=m;++j){
        int x=que[j].x,y=que[j].y;
        while(r<y){
            r++;
            sum-=nu[d[r]]*nu[d[r]];
            nu[d[r]]++;
            sum+=nu[d[r]]*nu[d[r]];
        }
        while(r>y){
            sum-=nu[d[r]]*nu[d[r]];
            nu[d[r]]--;
            sum+=nu[d[r]]*nu[d[r]];
            r--;
        }
        while(l<x){
            sum-=nu[d[l]]*nu[d[l]];
            nu[d[l]]--;
            sum+=nu[d[l]]*nu[d[l]];
            l++;
        }
        while(l>x){
            l--;
            sum-=nu[d[l]]*nu[d[l]];
            nu[d[l]]++;
            sum+=nu[d[l]]*nu[d[l]];
        }
        ans[que[j].id]=sum;
    }
    for(int i=1;i<=m;++i)    printf("%lld
",ans[i]);
    return 0;
}

/*
6 4 3
1 3 2 1 1 3
1 4
5 6
3 5
2 6
*/
原文地址:https://www.cnblogs.com/cellular-automaton/p/8270596.html