P8421 [THUPC2022 决赛] rsraogps
考虑离线。
我们从小到大枚举 ,考虑令 为 ,且 的答案。可以发现对于询问 ,答案即为 。
接着我们考虑当 时,对 的影响。
令 ,可以发现对于 ,增加的贡献应该为 的区间的价值之和。
可以发现,随着这个区间扩大,在 的次数内,按位与、按位或和 都会在某个区间 和 相等。
那么往前, 都会满足这样的性质。也就是贡献和上一次是一样的。
所以我们只需要暴力找到这个点 ,然后对于 暴力算贡献。
对于 ,其贡献和上一次他被暴力算的贡献是一样的。只需要令 为 被暴力算的时间戳即可。
整体的复杂度应该是 的。 是暴力求 的复杂度。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <numeric>
#include <vector>
using namespace std;
const int N = 5e6 + 5;
struct qer
{
int l, id;
qer(int _l, int _i) : l(_l), id(_i) {}
qer() {}
};
int n, m;
int a[N], b[N], c[N];
long long ans[N], val[N], q[N];
const long long MOD = 1LL << 32LL;
unsigned int tm[N], idx;
#define qr(p) (val[p] + q[p] * (idx - tm[p]) % MOD) % MOD
unsigned int ne[N], h[N], id;
qer e[N];
struct ios {
inline char read() {
static const int IN_LEN = 4500000;
static char buf[IN_LEN], * s, * t;
return (s == t) && (t = (s = buf) + fread(buf, 1, IN_LEN, stdin)), s == t ? -1 : *s++;
}
template <typename _Tp> inline ios& operator >> (_Tp& x) {
static char c11, boo;
for (c11 = read(), boo = 0; !isdigit(c11); c11 = read()) {
if (c11 == -1)return *this;
boo |= c11 == '-';
}
for (x = 0; isdigit(c11); c11 = read())x = x * 10 + (c11 ^ '0');
boo && (x = -x);
return *this;
}
}io;
int main()
{
memset(h, -1, sizeof h);
io >> n >> m;
for (int i = 1; i <= n; i++) io >> a[i];
for (int i = 1; i <= n; i++) io >> b[i];
for (int i = 1; i <= n; i++) io >> c[i];
for (int i = 1; i <= m; i++)
{
int l, r;
io >> l >> r;
e[id] = qer(l, i);
ne[id] = h[r];
h[r] = id++;
}
for (unsigned int i = 1; i <= n; i++)
{
unsigned int nowj = i;
for (unsigned int j = i - 1; j >= 1; j--)
{
unsigned int na(a[j] & a[j + 1]), nb(b[j] | b[j + 1]), nc(__gcd(c[j], c[j + 1]));
if (na == a[j] && nb == b[j] && nc == c[j]) break;
nowj = j; // 找到 p
a[j] = na, b[j] = nb, c[j] = nc; // 后缀一段的答案
}
val[i] = qr(i - 1);
for (int j = nowj; j <= i; j++)
{
val[j] = qr(j); // 先算一次之前的贡献
q[j] = q[j - 1] + 1LL * a[j] * b[j] * c[j]; // 把累计贡献加上去
q[j] %= MOD;
tm[j] = idx;
}
idx++; // 增加时间戳,以保证 a[j] * b[j] * c[j] 的贡献
for (int j = h[i]; ~j; j = ne[j])
{
qer k = e[j];
ans[k.id] = (qr(i) - qr(k.l - 1) + MOD) % MOD;
}
}
for (int i = 1; i <= m; i++) printf("%lld\n", ans[i]);
return 0;
}

浙公网安备 33010602011771号