莫队的各种杂题,博主真不要脸分明是水题

莫队这东西其实就是一种优化了的暴力,具体原理很好理解,不用我吹,复杂度证明也不用我吹。

NO.1:小Z的袜子

如题是一道水题,其实是莫队经典题,莫队就是出自这道题的。这道题是当年莫涛队长出的一道题,是第一道莫队题。

如果你会莫队就一定会,代码如下:

#include"cstdio"
#include"cmath"
#include"algorithm"
#include"cstring"
#include"iostream"
#define LL long long
#define Rep(i,n,x) for(i=x;i<=n;i++)
using namespace std;
struct mes
{
    LL l,r,ans1,ans2,dir;
};
mes c[50001];
LL a[50001],b[50001];
int k;
inline LL read()
{
    char c=getchar();int x=0;
    while(c<'0'||c>'9')c=getchar();
    while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
    return x;
}
bool cmp1(mes x,mes y)
{
    return ((x.l/k<y.l/k)||((x.l/k==y.l/k)&&(x.r<y.r)));
}
bool cmp2(mes x,mes y)
{
    return x.dir<y.dir;
}
inline void gcd(LL &x,LL &y)
{
    if(y==0)x=0,y=1;
    else
    { 
        int p1=x,p2=y;
        if(p1<p2)swap(p1,p2);
        while(p1!=0&&p2!=0)
        {
            p1=p1%p2;
            if(p1<p2)swap(p1,p2);
        }
        int p=p1?p1:p2;
        x/=p;y/=p;
    }	
}
int main()
{
    int n=read(),m=read();
    k=sqrt(n);
    int i;
    Rep(i,n,1)
        b[i]=read();
    LL l=1,r=0;
    Rep(i,m,1)
    {
        c[i].l=read(),c[i].r=read();
        c[i].dir=i;
    }
    sort(c+1,c+m+1,cmp1);
    memset(a,0,sizeof(a));
    LL ans=0;
    Rep(i,m,1)
    {
        while(l>c[i].l){
            l--;
            ans+=a[b[l]];
            a[b[l]]++;
        }
        while(r<c[i].r){
            r++;
            ans+=a[b[r]];
            a[b[r]]++;
        }
        while(l<c[i].l){
            a[b[l]]--;
            ans-=a[b[l]];
            l++;
        }
        while(r>c[i].r){
            a[b[r]]--;
            ans-=a[b[r]];
            r--;
        }
        c[i].ans1=ans;
        c[i].ans2=(r-l+1)*(r-l)/2;
        gcd(c[i].ans1,c[i].ans2);
    }
    sort(c+1,c+m+1,cmp2);
    Rep(i,m,1)
    printf("%lld/%lld\n",c[i].ans1,c[i].ans2);
    return 0;
}

第一次打莫队码风似乎有点骚。还有由于BZOJ很爆炸所以为了大家浏览方便些接了洛谷的链接。

NO.2:小B的询问

比小Z的袜子水,就更不用解说了。

代码如下:

#include"cstdio"
#include"algorithm"
#include"iostream"
#include"cmath"
#include"cstring"
#define LL long long
#define MAXN 50000+10
#define Rep(i,n,x) for(i=x;i<=n;i++)
using namespace std;
inline LL read()
{
    char c=getchar();LL x=0;
    while(c<'0'||c>'9')c=getchar();
    while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
    return x; 
}
struct asks
{
    LL l,r,NO,ans;
};
asks a[MAXN];
LL num[MAXN],cnt[MAXN],n,m,k,p;
bool cmp1(asks x,asks y)
{
    return ((x.l/p<y.l/p)||((x.l/p==y.l/p)&&(x.r<y.r)));
}
bool cmp2(asks x,asks y)
{
    return x.NO<y.NO;
}
int main()
{
    n=read(),m=read(),k=read();
    p=sqrt(n);
    int i;
    Rep(i,n,1)
    num[i]=read();
    Rep(i,m,1)
    {
        a[i].l=read(),a[i].r=read();
        a[i].NO=i;
    }
    sort(a+1,a+m+1,cmp1);
    memset(cnt,0,sizeof(cnt));
    LL l=1,r=0,ans=0;
    Rep(i,m,1)
    {
        while(l>a[i].l)
        {
            l--;
            ans+=cnt[num[l]]*2+1;
            cnt[num[l]]++;
        }
        while(r<a[i].r)
        {
            r++;
            ans+=cnt[num[r]]*2+1;
            cnt[num[r]]++;
        }
        while(l<a[i].l)
        {
            ans-=cnt[num[l]]*2-1;
            cnt[num[l]]--;
            l++;
        }
        while(r>a[i].r)
        {
            ans-=cnt[num[r]]*2-1;
            cnt[num[r]]--;
            r--;
        }
        a[i].ans=ans;
    }
    sort(a+1,a+m+1,cmp2);
    Rep(i,m,1)
    printf("%lld\n",a[i].ans);
    return 0;
} 

NO.3:数颜色

一道待修改的莫队,其实就是比普通莫队多加一维,这道题难度比上道高些。
#include"cstdio"
#include"algorithm"
#include"cmath"
#include"iostream"
#define Rep(i,n,x) for(i=x;i<=n;i++)
#define MAXN 10000+10
using namespace std;
struct asks
{
    int l,r,time,ans,dir;
};
asks a[MAXN];
int num[MAXN],anses[MAXN],n,m,p;
int color[1000001];
struct change
{
    int place,next;
};
change b[1002];
inline int read()
{
    char c=getchar();int x=0;
    while(c<'0'||c>'9')c=getchar();
    while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
    return x;
}
bool cmp(asks x,asks y)
{
    return ((x.l/p<y.l/p)||((x.l/p==y.l/p)&&(x.r/p<y.r/p))||((x.l/p==y.l/p)&&(x.r/p==y.r/p)&&(x.time<y.time)));
}
int turn(int now,int l,int r,int &ans)
{
    if(b[now].place>=l&&b[now].place<=r)
    {
        color[num[b[now].place]]--;
        if(color[num[b[now].place]]==0)
        ans--;
        color[b[now].next]++;
        if(color[b[now].next]==1)
        ans++;
    }
    swap(num[b[now].place],b[now].next);
}
int main()
{
    n=read(),m=read();
    int i,j;
    Rep(i,n,1)
        num[i]=read();
    int v=1,k=0;
    Rep(i,m,1)
    {
        char p1=getchar();
        while(p1!='Q'&&p1!='R')p1=getchar();
        if(p1=='Q')
        {
            a[++k].l=read();
            a[k].r=read();
            a[k].time=v;
            a[k].dir=k;
        }
        else
        {
            v++;
            b[v].place=read();
            b[v].next=read();
        }
    }
    p=sqrt(n);
    sort(a+1,a+k+1,cmp);
    int l=1,r=0,t=1,ans=0;
    Rep(i,k,1)
    {
        while(a[i].l<l){l--;color[num[l]]++;if(color[num[l]]==1)ans++;}
        while(r<a[i].r){r++;color[num[r]]++;if(color[num[r]]==1)ans++;}
        while(l<a[i].l){color[num[l]]--;if(color[num[l]]==0)ans--;l++;}
        while(r>a[i].r){color[num[r]]--;if(color[num[r]]==0)ans--;r--;}
        while(t<a[i].time){t++;turn(t,l,r,ans);}
        while(t>a[i].time){turn(t,l,r,ans);t--;}
        anses[a[i].dir]=ans;
    }
    Rep(i,k,1)
    printf("%d\n",anses[i]);
    return 0;
} 

NO.4:SDOI2009 HH的项链

naive,还可以用主席树来做,虽然很想用主席树来做但我还是忍住了(大雾)
代码如下:
#include"cstdio"
#include"cmath"
#include"algorithm"
#define MAXN 1000001
#define Rep(i,n,x) for(i=x;i<=n;i++)
using namespace std;
struct ask
{
    int l,r,dis;
};
inline int read()
{
    char c=getchar();int x=0;
    while(c<'0'||c>'9')c=getchar();
    while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
    return x;
}
ask asks[200001];
int color[MAXN];
int num[50001],anses[200001],p;
bool cmp(ask x,ask y)
{
    return ((x.l/p<y.l/p)||(x.l/p==y.l/p&&x.r<y.r));
}
int main()
{
    int n=read(),m;
    p=sqrt(n);
    int i;
    Rep(i,n,1)
    num[i]=read();
    m=read();
    Rep(i,m,1)
    asks[i].l=read(),asks[i].r=read(),asks[i].dis=i;
    sort(asks+1,asks+m+1,cmp);
    int l=1,r=0,ans=0;
    Rep(i,m,1)
    {
        while(l>asks[i].l){l--;color[num[l]]++;if(color[num[l]]==1)ans++;}
        while(r<asks[i].r){r++;color[num[r]]++;if(color[num[r]]==1)ans++;}
        while(l<asks[i].l){color[num[l]]--;if(color[num[l]]==0)ans--;l++;}
        while(r>asks[i].r){color[num[r]]--;if(color[num[r]]==0)ans--;r--;}
        anses[asks[i].dis]=ans;
    }
    Rep(i,m,1)
    printf("%d\n",anses[i]);
    return 0;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值