Codeforces455 D. Serega and Fun(序列分块+双端队列deque)

题意:

在这里插入图片描述
在这里插入图片描述

解法:
序列分块,每块大小为sqrt(n).

令cnt[i][j]为第i块中数字j的个数,这个可以O(n)预处理.

查询比较简单,就是普通的分块查询,复杂度O(sq).

循环右移操作:
左右两边的块O(sq)暴力循环右移,
中间的块如果暴力右移肯定不行,
一个快速循环右移的技巧是用双端队列deque,将末尾位置取出,放到开头就行了.
每块操作是O(1),因此操作O(sq)块的复杂度是O(sq).

综上:
算法总复杂度O(n*sq).
code:
#include <bits/stdc++.h>
using namespace std;
const int maxm=1e5+5;
int belong[maxm],l[maxm],r[maxm];
int cnt[333][maxm];
int num,block;
deque<int>d[333];
int a[maxm];
int n,q;
void init(){
    cin>>n;for(int i=1;i<=n;i++)cin>>a[i];
    block=sqrt(n);
    int num=n/block;if(n%block)num++;
    for(int i=1;i<=num;i++)l[i]=r[i-1]+1,r[i]=r[i-1]+block;
    r[num]=n;
    for(int i=1;i<=n;i++)belong[i]=(i-1)/block+1;
    for(int i=1;i<=n;i++)d[belong[i]].push_back(a[i]),cnt[belong[i]][a[i]]++;
}
void update(int ql,int qr){
    if(belong[ql]==belong[qr]){
        int x=belong[ql];int temp=d[x][qr-l[x]];
        for(int i=qr-l[x];i>ql-l[x];i--)d[x][i]=d[x][i-1];
        d[x][ql-l[x]]=temp;
    }else{
        int x=belong[qr];int temp=d[x][qr-l[x]];
        x=belong[ql];int last=d[x].back();cnt[x][last]--;
        for(int i=r[x]-l[x];i>ql-l[x];i--)d[x][i]=d[x][i-1];
        d[x][ql-l[x]]=temp;cnt[x][temp]++;
        for(int i=belong[ql]+1;i<belong[qr];i++){
            d[i].push_front(last);cnt[i][last]++;
            last=d[i].back();d[i].pop_back();cnt[i][last]--;
        }
        x=belong[qr];cnt[x][d[x][qr-l[x]]]--;
        for(int i=qr-l[x];i>l[x]-l[x];i--)d[x][i]=d[x][i-1];
        d[x][l[x]-l[x]]=last;cnt[x][last]++;
    }
}
int ask(int ql,int qr,int k){
    int ans=0;
    if(belong[ql]==belong[qr]){
        int x=belong[ql];
        for(int i=ql-l[x];i<=qr-l[x];i++)if(d[x][i]==k)ans++;
    }else{
        int x=belong[ql];
        for(int i=ql-l[x];i<=r[x]-l[x];i++)if(d[x][i]==k)ans++;
        x=belong[qr];
        for(int i=l[x]-l[x];i<=qr-l[x];i++)if(d[x][i]==k)ans++;
        for(int i=belong[ql]+1;i<belong[qr];i++)ans+=cnt[i][k];
    }
    return ans;
}
inline void solve(){
    init();
    int ans=0;
    cin>>q;while(q--){
        int op,ql,qr;cin>>op>>ql>>qr;
        ql=(ql+ans-1)%n+1,qr=(qr+ans-1)%n+1;
        if(ql>qr)swap(ql,qr);
        if(op==1){
            update(ql,qr);
        }else{
            int k;cin>>k;k=(k+ans-1)%n+1;
            ans=ask(ql,qr,k);
            cout<<ans<<endl;
        }
    }
}
signed main(){
    ios::sync_with_stdio(0);cin.tie(0);
    solve();
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值