P8264 [Ynoi Easy Round 2020] TEST_100 题解
题意:P8264 [Ynoi Easy Round 2020] TEST_100。
简要题意: 个数的序列 , 次询问,每次给定 ,求依次访问 每一个位置 ,执行 ,最终的 是什么。
范围:。时空限制: 秒, GB。
分块,设块长为 。
假如我们可以预处理出每一个数经过每一个块最终的结果,那么我们就容易做到 询问答案了。问题在于怎么求这个。
首先,最暴力的直接枚举 ,放进去跑,显然是不对的。考虑 有什么特性。他其实是一个分段函数,具体地,。于是我们可以确定,数 经过这个块中每个数后的结果,必然是一个一次函数,不妨设为 。进一步地,容易发现, 或 。
我们不妨设有一个函数 ,初始定义域和值域都是 ,动态维护当前函数的 和 。依次经过 时,只有三种情况,分别是 在值域左侧,右侧,或者之内。左侧和右侧的时候,我们发现分段函数其实只有一段,都可以修改函数表达式直接递归进下一个位置。但是在值域内的可能会被分为两段,如果分开,那么递归到下一个 需要分成两部分。
按照这个过程 DFS,我们得到了一个 的复杂度。取 可以平衡到 的复杂度,但是显然过不去。
考虑优化,复杂度瓶颈显然在于 的处理部分。但我们容易注意到绝对值函数 ,呈一个 V 字形,对称的位置是 。所以其实上述过程中把函数分为两部分的过程,本质上只需要递归进定义域大小更大的一部分,另一部分直接对称求出即可。
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
#include <vector>
#include <set>
#include <map>
using namespace std;
const int N = 1e5 + 5, M = 337;
int f[M][N];
int n, q, a[N];
int B;
int lans;
inline int get(int x)
{
return x / B;
}
inline int getL(int x)
{
return x * B;
}
int R;
int nowB;
void dfs(int l, int r, int k, int b, int u) // 定义域 [l,r]
{
if (l > r) return;
int zl = l * k + b, zr = r * k + b;
if (zl > zr) swap(zl, zr);
if (u == R)
{
for (int i = l; i <= r; i++)
{
f[nowB][i] = abs(i * k + b - a[R]);
}
return;
}
int p = a[u];
if (p > zr) // x -> p - x
{
dfs(l, r, -k, p - b, u + 1);
}
else if (p < zl)
{
dfs(l, r, k, b - p, u + 1);
}
else
{
int place = (p - b);
if (k >= 1)
{
int mid = place / k;
// [l, mid], (mid, r]
if (mid - l >= r - mid)
{
dfs(l, mid, -k, p - b, u + 1);
int nj = mid - 1;
for (int i = mid + 1; i <= r; i++)
{
f[nowB][i] = f[nowB][nj];
nj--;
}
}
else
{
dfs(mid, r, k, b - p, u + 1);
int nj = mid + 1;
for (int i = mid - 1; i >= l; i--)
{
f[nowB][i] = f[nowB][nj];
nj++;
}
}
}
else
{
int mid = place / k;
// [mid,r], [l,mid)
if (r - mid >= mid - l)
{
dfs(mid, r, -k, p - b, u + 1);
int nj = mid + 1;
for (int i = mid - 1; i >= l; i--)
{
f[nowB][i] = f[nowB][nj];
nj++;
}
}
else
{
dfs(l, mid, k, b - p, u + 1);
int nj = mid - 1;
for (int i = mid + 1; i <= r; i++)
{
f[nowB][i] = f[nowB][nj];
nj--;
}
}
}
}
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> q;
for (int i = 1; i <= n; i++) cin >> a[i];
B = sqrt(n);
int maxn = get(n);
memset(f, -1, sizeof f);
for (int i = 0; i <= maxn; i++)
{
int l = max(1, getL(i));
int r = min(n, getL(i + 1) - 1);
R = r;
nowB = i;
dfs(0, (int)1e5, 1, 0, l);
}
while (q--)
{
int l, r, v;
cin >> l >> r >> v;
l ^= lans, r ^= lans, v ^= lans;
if (get(l) == get(r))
{
int res = v;
for (int i = l; i <= r; i++) res = abs(res - a[i]);
cout << (lans = res) << "\n";
}
else
{
int gl = get(l), gr = get(r);
int res = v;
for (int i = l; i <= getL(gl + 1) - 1; i++) res = abs(res - a[i]);
for (int i = gl + 1; i < gr; i++) res = f[i][res];
for (int i = getL(gr); i <= r; i++) res = abs(res - a[i]);
cout << (lans = res) << "\n";
}
}
return 0;
}

浙公网安备 33010602011771号