莫队算法初步

参考博客:莫队算法——解决序列上询问的利器

题目:P2709 小B的询问

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 50005;
int a[maxn];
struct Node{
      int l, r, i;
}pos[maxn];
int ans = 0, block;
int cnt[maxn], res[maxn];
void Add(int x){//先减去之前的,更新一下,加上现在的
     ans -= cnt[a[x]]*cnt[a[x]];
     ++cnt[a[x]];
     ans += cnt[a[x]] * cnt[a[x]];
}
void Remove(int x){
     ans -= cnt[a[x]]*cnt[a[x]];
     --cnt[a[x]];
     ans += cnt[a[x]] * cnt[a[x]];
}
 inline int read(){
     int k=0;
     char c;
     c=getchar();
     while(!isdigit(c))c=getchar();
     while(isdigit(c)){k=(k<<3)+(k<<1)+c-'0';c=getchar();}
     return k;
 }
bool cmp(Node A, Node B){
     if(A.l / block == B.l/ block)return A.r < B.r;
     else return A.l < B.l;
}
int main(){
    int n, m, k;
    n = read();
    m = read();
    k = read();
    for(int i = 1; i <= n; i++){
        a[i] = read();
    }
        block = sqrt(n);
    for(int i = 1; i <= m; i++){
        pos[i].l = read();
        pos[i].r = read();
        pos[i].i = i;
    }
    sort(pos+1, pos+m+1, cmp);
    int L = 1, R = 0;
    ans = 0;
    for(int i = 1; i <= m; i++){
        while(L < pos[i].l){
            Remove(L++);
        }
        while(L > pos[i].l){
            Add(--L);
        }
        while(R < pos[i].r){
            Add(++R);
        }
        while(R > pos[i].r){
            Remove(R--);
        }
       // cout<<ans<<endl;
        res[pos[i].i] = ans;
    }
    for(int i = 1; i <= m; i++){
        printf("%d\n", res[i]);
    }
return 0;
}

题目:2038: [2009国家集训队]小Z的袜子(hose)

注意:这道题所有的数据都要开long long,不要问我为什么,我也不知道,因为这个卡了一个多点

下面的两组代码在更新的时候稍微有点差别,其他的都一样。

代码1:

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int maxn = 50005;
LL a[maxn];
struct Node
{
    LL l, r, i;
} pos[maxn];
LL gcd(LL a, LL b)
{
    if(!b)return a;
    else return gcd(b, a % b);
}
LL ans = 0;
LL block;
LL cnt[maxn], sum[maxn], res[maxn];
void Add(int x)
{
    ++cnt[a[x]];
    if(cnt[a[x]] > 1)
        ans += (cnt[a[x]]-1);
}
void Remove(int x)
{
    --cnt[a[x]];
    if(cnt[a[x]] > 0)ans -= cnt[a[x]];
}
bool cmp(Node A, Node B)
{
    if(A.l / block == B.l/ block)return A.r < B.r;
    else return A.l < B.l;
}
int main()
{
    LL n, m;
    scanf("%lld %lld", &n, &m);
    memset(cnt, 0, sizeof(cnt));
    for(int i = 1; i <= n; i++)
    {
        scanf("%lld", &a[i]);
    }
    block = sqrt(n);
    for(int i = 1; i <= m; i++)
    {
        scanf("%lld %lld", &pos[i].l, &pos[i].r);
        pos[i].i = i;
    }
    sort(pos+1, pos+m+1, cmp);
    LL L = 1, R = 0;
    ans = 0;
    for(int i = 1; i <= m; i++)
    {
        while(L < pos[i].l)
        {
            Remove(L++);
        }
        while(L > pos[i].l)
        {
            Add(--L);
        }
        while(R < pos[i].r)
        {
            Add(++R);
        }
        while(R > pos[i].r)
        {
            Remove(R--);
        }
        if(ans == 0)
        {
            res[pos[i].i] = 0;
            sum[pos[i].i] = 1;
        }
        LL result = (pos[i].r-pos[i].l+1)*(pos[i].r-pos[i].l)/2;
        LL t = gcd(result, ans);
        res[pos[i].i] = ans/t;
        sum[pos[i].i] = result/t;
    }
    for(int i = 1; i <= m; i++)
    {

        printf("%lld/%lld\n", res[i],sum[i]);
    }
    return 0;
}


代码2:

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int maxn = 50005;
LL a[maxn];
struct Node
{
    LL l, r, p;
} pos[maxn];
LL gcd(LL a, LL b)
{
    if(!b)return a;
    else return gcd(b, a % b);
}
LL ans = 0;
LL block;
LL cnt[maxn], sum[maxn], res[maxn];
void Add(int x)
{
    ans -= cnt[a[x]]*(cnt[a[x]] - 1) / 2;
    ++cnt[a[x]];
    ans += cnt[a[x]]*(cnt[a[x]] - 1) / 2;
}
void Remove(int x)
{
    ans -= cnt[a[x]]*(cnt[a[x]] - 1) / 2;
    --cnt[a[x]];
    ans += cnt[a[x]]*(cnt[a[x]] - 1) / 2;
}
bool cmp(Node A, Node B)
{
    if(A.l / block == B.l/ block)return A.r < B.r;
    else return A.l < B.l;
}
int main()
{
    LL n, m;
    scanf("%lld %lld", &n, &m);
    memset(cnt, 0, sizeof(cnt));
    for(int i = 1; i <= n; i++)
    {
        scanf("%lld", &a[i]);
    }
    block = sqrt(n);
    for(int i = 1; i <= m; i++)
    {
        scanf("%lld %lld", &pos[i].l, &pos[i].r);
        pos[i].p = i;
    }
    sort(pos+1, pos+m+1, cmp);
    LL L = 1, R = 0;
    ans = 0;
    for(int i = 1; i <= m; i++)
    {
        while(L < pos[i].l)
        {
            Remove(L++);
        }
        while(L > pos[i].l)
        {
            Add(--L);
        }
        while(R < pos[i].r)
        {
            Add(++R);
        }
        while(R > pos[i].r)
        {
            Remove(R--);
        }
        if(ans == 0)
        {
            res[pos[i].p] = 0;
            sum[pos[i].p] = 1;
        }
        LL result = (pos[i].r-pos[i].l+1)*(pos[i].r-pos[i].l)/2;
        LL t = gcd(result, ans);
        res[pos[i].p] = ans/t;
        sum[pos[i].p] = result/t;
    }
    for(int i = 1; i <= m; i++)
    {

        printf("%lld/%lld\n", res[i],sum[i]);
    }
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值