莫队算法+练习题题解+快读

自己开的练习赛:(三个模板题)
https://vjudge.net/contest/239597#problem

莫队算法:给定一个区间(l,r)的结果,求问(l+1,r),(l,r+1),(l-1,r)(l,r-1);
核心:
一个修改函数;(先减去之前的,挪到现在的位置,加上现在的)
四个while;
这里写图片描述
(先更新,再挪L);
这里写图片描述

这里写图片描述
这里写图片描述

模板:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long int ll;
const int N=3e5+5;
const int MAX=1e6+5;
int unit,arr[N];
ll ans=0,pes[N],res[N],cnt[MAX];
struct node
{
    int l,r,id;
} q[N];
bool cmp(node a,node b)
{
    return a.l/unit!=b.l/unit?a.l/unit<b.l/unit:a.r<b.r;
}
void add(int pos)  //减去原来的位置,加上现在的位置
{
    ans=ans-cnt[arr[pos]]*cnt[arr[pos]];
    cnt[arr[pos]]++;
    ans=ans+cnt[arr[pos]]*cnt[arr[pos]];

}
void remove(int pos)//减去原来的位置,加上现在的位置
{
    ans=ans-cnt[arr[pos]]*cnt[arr[pos]];
    cnt[arr[pos]]--;
    ans=ans+cnt[arr[pos]]*cnt[arr[pos]];
}
int main()
{
    int n,m;
    scanf("%d",&n);
    scanf("%d",&m);
    unit=sqrt(n);
    for(int i=1; i<=n; i++)
    {
        scanf("%d",&arr[i]);
    }
    for(int i=1; i<=m; i++)
    {
        scanf("%d%d",&q[i].l,&q[i].r);
        q[i].id=i;
    }
    sort(q+1,q+m+1,cmp);
    int L=q[1].l,R=L-1;
    for(int i=1; i<=m; i++)
    {
        while(L>q[i].l)
            add(--L);
        while(L<q[i].l)
            remove(L++);
        while(R>q[i].r)
            remove(R--);
        while(R<q[i].r)
            add(++R);
        res[q[i].id]=ans-(R-L+1);
        pes[q[i].id]=(ll)(R-L+1)*(R-L);
    }
    for(int i=1; i<=m; i++)
    {
        ll p=__gcd(res[i],pes[i]);
        printf("%lld/%lld\n",res[i]/p,pes[i]/p);
    }
}

第一个题:
题意:一个区间内不同的数有多少个;

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=3e5+5;//区间范围
const int MAX=1e6+5;//最大数字
int unit,cnt[MAX],arr[N],res[N],ans=0;
struct node
{
    int l,r,id;
} q[N];

bool cmp(node a,node b)
{
    return a.l/unit!=b.l/unit?a.l/unit<b.l/unit:a.r<b.r;
}

void add(int pos)
{
    cnt[arr[pos]]++;
    if(cnt[arr[pos]]==1)
    {
        ans++;
    }
}

void remove(int pos)
{
    cnt[arr[pos]]--;
    if(cnt[arr[pos]]==0)
    {
        ans--;
    }
}

int main()
{
    int n;
    scanf("%d",&n);
    unit=sqrt(n);
    for(int i=1; i<=n; i++)
    {
        scanf("%d",&arr[i]);
    }
    int m;
    scanf("%d",&m);
    for(int i=1; i<=m; i++)
    {
        scanf("%d%d",&q[i].l,&q[i].r);
        q[i].id=i;
    }
    sort(q+1,q+m+1,cmp);

    int L=q[1].l,R=L-1;
    for(int i=1; i<=m; i++)
    {
        while(L>q[i].l)
            add(--L);
        while(L<q[i].l)
            remove(L++);
        while(R>q[i].r)
            remove(R--);
        while(R<q[i].r)
            add(++R);
        res[q[i].id]=ans;
    }
    for(int i=1; i<=m; i++)
    {
        printf("%d\n",res[i]);
    }
}

第二个题:
小z的袜子;
求概率:
本题公式:((a^2+b^2+……)-(R-L+1))/((R-L+1)*(R-L))

代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long int ll;
const int N=3e5+5;
const int MAX=1e6+5;
int unit,arr[N];
ll ans=0,pes[N],res[N],cnt[MAX];
struct node
{
    int l,r,id;
} q[N];
bool cmp(node a,node b)
{
    return a.l/unit!=b.l/unit?a.l/unit<b.l/unit:a.r<b.r;
}
void add(int pos)  //减去原来的位置,加上现在的位置
{
    ans=ans-cnt[arr[pos]]*cnt[arr[pos]];
    cnt[arr[pos]]++;
    ans=ans+cnt[arr[pos]]*cnt[arr[pos]];

}
void remove(int pos)//减去原来的位置,加上现在的位置
{
    ans=ans-cnt[arr[pos]]*cnt[arr[pos]];
    cnt[arr[pos]]--;
    ans=ans+cnt[arr[pos]]*cnt[arr[pos]];
}
int main()
{
    int n,m;
    scanf("%d",&n);
    scanf("%d",&m);
    unit=sqrt(n);
    for(int i=1; i<=n; i++)
    {
        scanf("%d",&arr[i]);
    }
    for(int i=1; i<=m; i++)
    {
        scanf("%d%d",&q[i].l,&q[i].r);
        q[i].id=i;
    }
    sort(q+1,q+m+1,cmp);
    int L=q[1].l,R=L-1;
    for(int i=1; i<=m; i++)
    {
        while(L>q[i].l)
            add(--L);
        while(L<q[i].l)
            remove(L++);
        while(R>q[i].r)
            remove(R--);
        while(R<q[i].r)
            add(++R);
        res[q[i].id]=ans-(R-L+1);
        pes[q[i].id]=(ll)(R-L+1)*(R-L);
    }
    for(int i=1; i<=m; i++)
    {
        ll p=__gcd(res[i],pes[i]);
        printf("%lld/%lld\n",res[i]/p,pes[i]/p);
    }
}

第三个题:
题意:(p[y]*p[y]*y的和)p[y]:数值为y的数出现的个数;

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long int ll;
const int maxn=200005;
const int maxa=1e6;
int n,m;
struct node
{
    int l,r,id;
} q[maxn];
int cmp(const node& a,const node& b){
    if(a.l/(int)sqrt(m)!=b.l/(int)sqrt(m))  return a.l/(int)sqrt(m)<b.l/(int)sqrt(m);
    return a.r<b.r;
}
int arr[maxn];
int cnt[maxa+5];
ll ans,res[maxn];
void update(int cur,int change)
{
    ans-=(ll)cnt[arr[cur]]*cnt[arr[cur]]*arr[cur];
    cnt[arr[cur]]+=change;
    ans+=(ll)cnt[arr[cur]]*cnt[arr[cur]]*arr[cur];
}

void solve()
{
    ans=arr[1];
    cnt[arr[1]]++;
    int L=1;
    int R=1;
    for(int i=1; i<=m; i++)
    {
        while(L<q[i].l)
        {
            update(L,-1);
            L++;
        }
        while(L>q[i].l)
        {
            L--;
            update(L,1);
        }
        while(R>q[i].r)
        {
            update(R,-1);
            R--;
        }
        while(R<q[i].r)
        {
            R++;
            update(R,1);
        }

        res[q[i].id]=ans;
    }
}

int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&arr[i]);
        }
        for(int i=1; i<=m; i++)
        {
            scanf("%d%d",&q[i].l,&q[i].r);
            q[i].id=i;
        }
        sort(q+1,q+m+1,cmp);
        memset(cnt,0,sizeof(cnt));
        solve();
        for(int i=1; i<=m; i++)
        {
            cout<<res[i];
            printf("\n");
        }
    }
}

快速读入,快速输出:
(由于putchar()比scanf,print快);

int read()
{
    ll x=0;
    char c=getchar();
    while(c < '0' || c > '9')
    {
        c = getchar();
    }
    while(c >= '0' && c <= '9')
    {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x;
}
void out(ll x)
{
    if(x < 0)
    {
        putchar('-');
        x = -x;
    }
    if (x >= 10)
    {
        out(x / 10);
    }
    putchar(x % 10 + '0');
}

            //arr[i]=read();
            //q[i].l=read();
           // q[i].r=read();
            //out(res[i]);

莫队的另一个题:牛客网暑假acm第一次多校训练:
(j签到题)(包含了莫队及输入输出)

#include <bits/stdc++.h>
using namespace std;
struct papp
{
    int l;
    int r;
    int id;
} a[200005];
int read()
{
    int x=0;
    char c=getchar();
    while(c < '0' || c > '9')
    {
        c = getchar();
    }
    while(c >= '0' && c <= '9')
    {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x;
}
void out(int x)
{
    if(x < 0)
    {
        putchar('-');
        x = -x;
    }
    if (x >= 10)
    {
       out(x / 10);
    }
    putchar(x % 10 + '0');
}
int ma;
int cmp(papp a,papp b)
{
    if(a.l/ma==b.l/ma)
    {
        return a.r<b.r;
    }
    else
    {
        return a.l/ma<b.l/ma;
    }
}
int sum,num[200005],ans[200005];
void pan(int n)
{
    num[n]++;
    if(num[n]==1)
    {
        sum++;
    }
}
void pan1(int n)
{
    num[n]--;
    if(num[n]==0)
    {
        sum--;
    }
}
int str[200005];
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        sum=0;
        memset(ans,0,sizeof(ans));
        memset(num,0,sizeof(num));
        int l=0,r=0;
        ma=sqrt(n);
        for(int i=1; i<=n; i++)
        {
            str[i]=read();
            str[n+i]=str[i];
        }
        int x1,x2;
        for(int i=1; i<=m; i++)
        {
            x1=read();
            x2=read();
            a[i].l=x2;
            a[i].r=x1+n;
            a[i].id=i;
        }
        sort(a+1,a+m+1,cmp);
        l=a[1].l,r=l-1;
        for(int i=1; i<=m; i++)
        {
            while(r<a[i].r)
            {
                r++,pan(str[r]);
            }
            while(r>a[i].r)
            {
                pan1(str[r]),r--;
            }
            while(l<a[i].l)
            {
                pan1(str[l]),l++;
            }
            while(l>a[i].l)
            {
                l--,pan(str[l]);
            }
            ans[a[i].id]=sum;
        }
        for(int i=1; i<=m; i++)
        {
            out(ans[i]);
            printf("\n");
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/wuxiaowu547/article/details/81141677
今日推荐