[CF455D] Serega and Fun - 分块
Description
给定长度为N(N<=100000)的序列,支持两种操作:1 l r 将区间l到r依次向右移动一位,a[r]移动到 [l],2 l r k 询问区间l到r中k出现次数。
Solution
考虑分块,每个块内用 deque 维护(这个东西好处就在于不仅支持双端操作还可以下标索引),同时维护一个块内每个值的出现次数
然后对于操作就暴力处理一下
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int B = 360;
const int N = 100005;
int block(int x)
{
return x / B;
}
int offset(int x)
{
return x % B;
}
deque<int> a[B];
signed c[B][N];
int n, q;
signed main()
{
ios::sync_with_stdio(false);
cin >> n;
for (int i = 0; i < n; i++)
{
int x;
cin >> x;
a[block(i)].push_back(x);
c[block(i)][x]++;
}
cin >> q;
int lastans = 0;
for (int i = 0; i < q; i++)
{
int op, l, r, k;
cin >> op >> l >> r;
l = (l + lastans - 1) % n;
r = (r + lastans - 1) % n;
if (l > r)
swap(l, r);
if (op == 2)
cin >> k;
k = (k + lastans - 1) % n + 1;
int L = block(l);
int R = block(r);
l = offset(l);
r = offset(r);
if (op == 1)
{
if (L == R)
{
int x = a[R][r];
a[R].erase(a[R].begin() + r);
a[L].insert(a[L].begin() + l, x);
}
else
{
for (int i = L; i < R; i++)
{
int x = a[i].back();
a[i].pop_back();
c[i][x]--;
c[i + 1][x]++;
a[i + 1].push_front(x);
}
int x = a[R][r + 1];
a[R].erase(a[R].begin() + r + 1);
a[L].insert(a[L].begin() + l, x);
c[R][x]--;
c[L][x]++;
}
}
else
{
int ans = 0;
if (L == R)
{
for (int i = l; i <= r; i++)
ans += a[L][i] == k;
}
else
{
for (int i = l; i < a[L].size(); i++)
ans += a[L][i] == k;
for (int i = 0; i <= r; i++)
ans += a[R][i] == k;
for (int i = L + 1; i <= R - 1; i++)
ans += c[i][k];
}
cout << (lastans = ans) << endl;
}
}
}