莫队算法模板

本文介绍莫队算法的基本原理及其实现方法,通过两道例题详细展示了莫队算法的应用场景和编写技巧。第一道题为简单的莫队算法实现,第二道题则结合了分块思想进一步提高了解决大规模数据集的能力。

一道简单的莫队算法题:
https://vjudge.net/contest/171364#problem/I
莫队的一般写法:

// CodeForces 86D
#include<bits/stdc++.h>
#define pb push_back 
#define mp make_pair
using namespace std;

const int maxn=2e5+7;
typedef long long ll;

struct Mo{
    int l,r,t,id;
}p[maxn];

ll a[maxn];

ll f[1000007];

ll ans[maxn];

int n,Q;

ll now=0;

bool operator<(const Mo &a,const Mo &b)
{
    if(a.t==b.t) return a.r<b.r;
    return a.t<b.t;
}

void dec(int x)
{
    ll v=a[x];
    now+=(-2*f[v]+1)*v;
    f[v]--;
}

void add(int x)
{
    ll v=a[x];
    now+=(2*f[v]+1)*v;
    f[v]++;
}

int main()
{
    int i,j,k,T;
    scanf("%d%d",&n,&Q);
    for(i=1;i<=n;++i)
    {
        scanf("%lld",&a[i]);
    }
    int q=700;
    for(i=1;i<=Q;++i)
    {
        scanf("%d%d",&p[i].l,&p[i].r);
        p[i].t=p[i].l/q;
        p[i].id=i;
    }

    sort(p+1,p+Q+1);

    int l=1,r=0;
    for(i=1;i<=Q;++i)
    {
        while(l<p[i].l) dec(l++);
        while(l>p[i].l) add(--l);
        while(r<p[i].r) add(++r);
        while(r>p[i].r) dec(r--);
        ans[p[i].id]=now;
    }

    for(i=1;i<=Q;++i)
    {
        printf("%I64d\n",ans[i]);
    } 

    return 0;
}

稍难一点的莫队(莫队+分块)
http://acm.uestc.edu.cn/#/problem/show/1753
别人的题解:
http://hzwer.com/5749.html
我的代码:

// UESTC - 1753
#include<bits/stdc++.h>
#define pb push_back 
#define mp make_pair
using namespace std;

const int maxn=1e5+7,maxm=1e6+7;
typedef long long ll;

//快速读入 
inline void read(int &n)
{
    char ch=' ';int q=0,w=1;
    for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
    if(ch=='-')w=-1,ch=getchar();
    for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;
    n=q*w;
}
//快速输出
inline void write(int x){  
    static const int maxlen=100;  
    static char s[maxlen];  
        if (x<0) {   putchar('-'); x=-x;}  
    if(!x){ putchar('0'); return; }  
    int len=0; for(;x;x/=10) s[len++]=x % 10+'0';  
    for(int i=len-1;i>=0;--i) putchar(s[i]);  
} 

struct Mo{
    int l,r,id,a,b;
}p[maxm];

int ans[maxm];

int n,m;

struct Part{
    int l,r,num;
}part[maxn];

int f[maxn],s[maxn];

int ntop[maxn];

int q;

bool operator<(const Mo &a,const Mo &b)
{
    if(a.l/q==b.l/q) return a.r<b.r;
    return a.l/q<b.l/q;
}

void add(int x)
{
    int v=s[x];
    f[v]++;
    if(f[v]==1) part[ntop[v]].num++;
}

void dec(int x)
{
    int v=s[x];
    f[v]--;
    if(f[v]==0) part[ntop[v]].num--;
}

int get_ans(int l,int r)
{
    int L=ntop[l],R=ntop[r];
    int res=0,i;
    if(L==R)
    {
        for(i=l;i<=r;++i)
        {
            if(f[i])
              res++;
        }
        return res;
    }
    for(i=L+1;i<=R-1;++i)
      res+=part[i].num;
    for(i=l;i<=part[L].r;++i)
      if(f[i]) res++;
    for(i=part[R].l;i<=r;++i)
      if(f[i]) res++;
    return res;
}

void doit_mo()
{
    int l=1,r=0;
    for(int i=1;i<=m;++i)
    {
        while(l<p[i].l) dec(l++);
        while(l>p[i].l) add(--l);
        while(r<p[i].r) add(++r);
        while(r>p[i].r) dec(r--);
        ans[p[i].id]=get_ans(p[i].a,p[i].b);
    }
}

int main()
{
    int i,j,k,T;
    read(n);read(m);

    q=sqrt(n);

    for(i=1;i<=n;++i)
    {
        ntop[i]=(i-1)/q+1;
    }

    for(i=1;i<=n;i+=q)
    {
        part[ntop[i]].l=i;
        part[ntop[i]].r=i+q-1;
    }

    for(i=1;i<=n;++i) 
    {
        read(s[i]);
    }
    for(i=1;i<=m;++i)
    {
        read(p[i].l);
        read(p[i].r);
        read(p[i].a);
        read(p[i].b);
        p[i].id=i;
    }

    sort(p+1,p+1+m);

    doit_mo();


    for(i=1;i<=m;++i)
      write(ans[i]),putchar('\n');
    /*
    for(i=1;i<=m;++i)
      printf("%d\n",ans[i]);
    */
    return 0;
}

————————
关于分块的方法:
这里写图片描述
用刘大爷的话说,第一种满足基本复杂度,第二种在m很大时更优
————————
当带上修改时:
http://blog.youkuaiyun.com/hzj1054689699/article/details/51866615

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值