csu1515 squence 莫队算法

本文通过一道具体题目介绍了莫队算法的应用,详细讲解了如何利用分块思想优化查询操作,并给出了完整的实现代码。适合对莫队算法感兴趣或希望提高算法实战能力的读者。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

莫队大法好,分块一同乱搞。

远哥出的题,当时没做出来,今天才学会莫队。

如果[l,r] -> [l,r+1] 可以在o(1)时间内求出,就可以sqrt(n)分块后,对询问排序更新。

因为我写的太丑了,必须用输入外挂才过了。

复杂度msqrt(n)

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<map>
using namespace std;
const int N = 1e5 +10;
typedef long long ll;
map<ll,ll> mm;
struct quest
{
    int l,r,id;
    ll ans;
}p[N];
int pos[N],col[N],s[N],n,m;
ll ans = 0;
int cmp(quest a,quest b)
{
    if(pos[a.l] == pos[b.l] ) return a.r < b.r;
    return a.l < b.l;
}
int cmp2(quest a,quest b)
{
    return a.id < b.id;
}
void update(int q,int x){
    ll c = col[q];
    ll t1 = mm[c-1] ,t3 = mm[c+1];
    mm[c] += x;
    ans += x*(t1+t3);
}
void solve()
{
    int l,r;
    for(int i=1,l=1,r=0;i<=m;i++){
        for(;r<p[i].r;r++)
            update(r+1,1);
        for(;r>p[i].r;r--)
            update(r,-1);
        for(;l<p[i].l;l++)
            update(l,-1);
        for(;l>p[i].l;l--)
            update(l-1,1);
        p[i].ans = ans;
    }
}
void in(int &x){
    char ch; int minus = 0;
    while (ch=getchar(), (ch<'0'||ch>'9') && ch!='-');
    if (ch == '-') minus = 1, x = 0;
    else x = ch-'0';
    while (ch=getchar(), ch>='0'&&ch<='9') x = x*10+ch-'0';
    if (minus) x = -x;
}

void out(ll x){
    char hc[30];int len, minus=0;
    if (x<0) minus = 1, x = -x;
    len = 0; hc[len++] = x%10+'0';
    while (x/=10) hc[len++] = x%10+'0';
    if (minus) putchar('-');
    for (int i=len-1; i>=0; i--) putchar(hc[i]);
}

int main()
{
    while(scanf("%d%d",&n,&m)!=EOF){
        ans = 0;
        int block = (int) sqrt(n);
        for(int i=1;i<=n;i++) pos[i] = i/block + 1;
        mm.clear();
        for(int i=1;i<=n;i++){
            int b; in(b);
            mm[b] = mm[b-1] = mm[b+1] = 0;
            col[i] = b;
        }
        //for(int i=1;i<=n;i++) printf("# %d\n",col[i]);
        for(int i=1;i<=m;i++){
            //scanf("%d%d",&p[i].l,&p[i].r);
            in(p[i].l); in(p[i].r);
            p[i].id = i;
        }
        sort(p+1,p+1+m,cmp);
        solve();
        sort(p+1,p+1+m,cmp2);
        for(int i=1;i<=m;i++){
            //printf("%lld\n",p[i].ans);
            out(p[i].ans);
            printf("\n");
        }
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值