P4135 作诗
分块经典题。
这种题显然是数据结构,,考虑根号复杂度做法。于是考虑使用分块。
我们先预处理出两个值:, 表示第 块到第 块的答案, 表示从第 块到第 块中 出现的次数。
那么若要求第 块到第 块中 出现的次数,保证 ,就是 。查询同块暴力,不同块的时候先求整块,然后对零散块求出与整块的答案的差即可。
复杂度 。
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <map>
#include <cstring>
#include <unordered_map>
using namespace std;
const int N = 1e5 + 5, M = 325;
int n, m, c;
int a[N], ans = 0, l, r;
int bel[N], block;
int mph[N];
bool vis[N];
int g[M][N], res[M][M];
#define L(x) ((x - 1) * block)
#define get(l, r, x) (l > r ? 0 : g[r][x] - g[l - 1][x])
int main()
{
scanf("%d%d%d", &n, &c, &m);
block = sqrt(n);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]), bel[i] = i / block + 1;
for (int i = 1; i <= bel[n]; i++)
{
for (int j = 0; j <= c; j++) g[i][j] = g[i - 1][j];
int l = L(i), r = L(i + 1) - 1;
for (int j = l; j <= r; j++) g[i][a[j]]++;
}
for (int i = 1; i <= bel[n]; i++)
{
for (int j = i; j <= bel[n]; j++)
{
res[i][j] = res[i][j - 1];
int l = L(j), r = L(j + 1) - 1;
for (int k = l; k <= r; k++)
{
if (vis[a[k]]) continue;
int pre = get(i, j - 1, a[k]), now = get(j, j, a[k]);
if (pre == 0)
{
if (!(now & 1)) res[i][j]++;
}
else if (pre % 2 != (pre + now) % 2)
{
if (pre % 2) res[i][j]++;
else res[i][j]--;
}
vis[a[k]] = true;
}
for (int k = l; k <= r; k++) vis[a[k]] = false;
}
}
while (m--)
{
int l, r;
scanf("%d%d", &l, &r);
l = (l + ans) % n + 1, r = (r + ans) % n + 1;
if (l > r) swap(l, r);
ans = 0;
if (bel[l] == bel[r])
{
for (int i = l; i <= r; i++)
{
mph[a[i]]++;
}
for (int i = l; i <= r; i++)
{
int x = mph[a[i]];
if (x > 0 && x % 2 == 0) ans++;
mph[a[i]] = 0;
}
}
else
{
int nl = bel[l] + 1, nr = bel[r] - 1;
int rl = L(bel[l] + 1) - 1, lr = L(bel[r]);
ans = res[nl][nr];
for (int i = l; i <= rl; i++) mph[a[i]]++;
for (int i = lr; i <= r; i++) mph[a[i]]++;
for (int i = l; i <= rl; i++)
{
if (vis[a[i]]) continue;
int pre = get(nl, nr, a[i]), now = mph[a[i]];
if (pre == 0)
{
if (!(now & 1)) ans++;
}
else if (pre % 2 != (pre + now) % 2)
{
if (pre & 1) ans++;
else ans--;
}
vis[a[i]] = true;
mph[a[i]] = 0;
}
for (int i = lr; i <= r; i++)
{
if (vis[a[i]]) continue;
int pre = get(nl, nr, a[i]), now = mph[a[i]];
if (pre == 0)
{
if (!(now & 1)) ans++;
}
else if (pre % 2 != (pre + now) % 2)
{
if (pre & 1) ans++;
else ans--;
}
vis[a[i]] = true;
mph[a[i]] = 0;
}
for (int i = l; i <= rl; i++) vis[a[i]] = false;
for (int i = lr; i <= r; i++) vis[a[i]] = false;
}
printf("%d\n", ans);
}
return 0;
}

浙公网安备 33010602011771号