莫队是一个优美的暴力

   当我们可以在 O(1) 时间推到 L[i-1], L[i+1] , R[i-1] , R[i+1] 的时候 ,就可以使用莫队来解决这个问题啦

  

  一  普通莫队

  首先分块,将询问的区间按照左端点所处的块来排序,然后按顺序处理每一个询问就好了

  这里有一个小 trick ,排序的时候可以按照块的奇偶性来排序,可以大大的提高效率,虽然我并不知道为什么。

  

  经典例题: 小Z的袜子

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<stack>
#include<queue>
using namespace std;
typedef long long ll;

const int maxn = 100010;

int n,m,blo;
int l=1,r=0;
int c[maxn],cnt[maxn],pos[maxn];
ll res=0;

struct Q{
    int l,r,id;
}q[maxn];
struct Ans{
    ll a,b;
}ans[maxn];

bool cmp(Q a,Q b){
    if(pos[a.l]==pos[b.l]) return a.r<b.r;
    return a.l<b.l;
}

void add(int i){
    res-=1ll*cnt[c[i]]*cnt[c[i]];
    ++cnt[c[i]];
    res+=1ll*cnt[c[i]]*cnt[c[i]];
}

void del(int i){
    res-=1ll*cnt[c[i]]*cnt[c[i]];
    --cnt[c[i]];
    res+=1ll*cnt[c[i]]*cnt[c[i]];
}

ll gcd(ll a,ll b){
    if(a<b) swap(a,b); 
    return b==0?a:gcd(b,a%b);
}

ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; }

int main(){
    n=read(),m=read();
    blo=sqrt(n);
    for(int i=1;i<=n;i++) c[i]=read(),pos[i]=(i-1)/blo+1;
    for(int i=1;i<=m;i++){
        q[i].l=read(),q[i].r=read();
        q[i].id=i;
    }
    
    sort(q+1,q+1+m,cmp); 
    
    for(int i=1;i<=m;i++){
        while(l<q[i].l){ del(l); l++; }
        while(l>q[i].l){ add(l-1); l--; }
        while(r<q[i].r){ add(r+1); r++; }
        while(r>q[i].r){ del(r); r--; }
        
        if(q[i].l==q[i].r){
            ans[q[i].id]=(Ans){0,1};
            continue;
        }
        ans[q[i].id]=(Ans){res-(r-l+1),1ll*(r-l+1)*(r-l)};
    }
    
    for(int i=1;i<=m;i++){
        ll g=gcd(ans[i].a,ans[i].b);
        printf("%lld/%lld\n",ans[i].a/g,ans[i].b/g); 
    }
    
    return 0;
}
View Code

相关文章: