莫队

莫队就是离线处理一些问题。

当一个问题[l,r]可以由[l-1,r],[l,r+1],[l+1,r],[l,r-1]相差一的区间由O(1)或O(logn)推出时,就可以用莫队莫队实质上是离线处理,通过改变询问的顺序使复杂度降到O(n^1.5)

其实莫队用到分块的地方仅仅是排序中用到?

排序的过程:先计算每个位置应该处于哪个块中,记为pos[i],按(pos[i],r)双关键字排序,然后再对每个区间暴力计算

bzoj2038&&bzoj3781

题解太多了

大概就是个裸的莫队

bzoj2038

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
struct data
{
    ll a,b;
    int l,r,id;
}a[100010];
int n,m;
ll tot;
int c[100010];
ll cnt[100010],pos[100010];
ll gcd(ll a,ll b)
{
    return b==0?a:gcd(b,a%b);
}
bool cp1(data x,data y)
{
    if(pos[x.l]!=pos[y.l]) return pos[x.l]<pos[y.l];
    return x.r<y.r;
}
bool cp2(data x,data y)
{
    return x.id<y.id;
}
void update(int x,int delta)
{
    tot-=cnt[c[x]]*(cnt[c[x]]-1)/2;
    cnt[c[x]]+=delta;
    tot+=cnt[c[x]]*(cnt[c[x]]-1)/2;
}
void solve()
{
    for(int i=1,l=1,r=0;i<=m;i++)
    {
//        printf("a[i].l=%d a[i].r=%d\n",a[i].l,a[i].r);
        while(r<a[i].r) {
            r++; update(r,1);
        }
        while(r>a[i].r) {
            update(r,-1); r--; 
        }
        while(l<a[i].l) {
            update(l,-1); l++; 
        }
        while(l>a[i].l) {
            l--; update(l,1);
        }
        if(a[i].l==a[i].r)
        {
            a[i].a=0; a[i].b=1;
            continue;
        }
//        for(int j=1;j<=n;j++)
//        {
//            printf("color[%d]=%d\n",c[j],cnt[c[j]]);
//        }
//        printf("l=%d r=%d\n",l,r);
//        printf("tot=%d\n",tot);
        a[i].a=tot; a[i].b=(ll)(a[i].r-a[i].l+1)*(ll)(a[i].r-a[i].l)/2;
        ll k=gcd(a[i].b,a[i].a);
        a[i].a/=k;
        a[i].b/=k;
        if(a[i].a==0) a[i].b=1;
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&c[i]);
    } 
    int size=(int)(sqrt(n));
    for(int i=1;i<=n;i++)
    {
        pos[i]=(i-1)/size+1;
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&a[i].l,&a[i].r);
        a[i].id=i;
    }
    sort(a+1,a+m+1,cp1);
    solve();
    sort(a+1,a+m+1,cp2);
    for(int i=1;i<=m;i++)
    {
        printf("%lld/%lld\n",a[i].a,a[i].b);
    }
    return 0;
}

bzoj3781

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define N 500010
struct data 
{
    int l,r,pos,ans;
}a[N];
int n,m,k,ans;
int cnt[N],c[N],pos[N];
bool cp(data x,data y)
{
    if(pos[x.l]!=pos[y.l]) return pos[x.l]<pos[y.l];
    return x.r<y.r;
}
bool cp1(data x,data y)
{
    return x.pos<y.pos;
}
void update(int pos,int delta)
{
    ans-=cnt[c[pos]]*cnt[c[pos]];
    cnt[c[pos]]+=delta;
    ans+=cnt[c[pos]]*cnt[c[pos]];
}
void solve()
{
    int l=1,r=0;
    for(int i=1;i<=m;i++)
    {
//        printf("a[i].l=%d a[i].r=%d\n",a[i].l,a[i].r);
        while(l<a[i].l) {
            update(l,-1); l++; 
        }
        while(l>a[i].l) {
            l--; update(l,1); 
        }
        while(r>a[i].r) {
            update(r,-1); r--; 
        }
        while(r<a[i].r) {
            r++; update(r,1); 
        }
        a[i].ans=ans;
    }
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    int size=(int)(sqrt(n));
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&c[i]);
        pos[i]=(i-1)/size+1;
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&a[i].l,&a[i].r);
        a[i].pos=i;
    }
    sort(a+1,a+m+1,cp);
    solve();
    sort(a+1,a+m+1,cp1);
    for(int i=1;i<=m;i++)
    {
        printf("%d\n",a[i].ans);
    }
    return 0;
}

 

posted @ 2016-12-14 22:06  19992147  阅读(270)  评论(0编辑  收藏  举报