P6604 [HNOI2016] 序列 加强版 题解
与最小值相关,考虑求出每个点左右两边第一个小于这个数的点。可以用笛卡尔树或者单调栈维护。
设 表示以 为右端点的所有区间的最小值之和。考虑如何转移 。
设 左边第一个小于 的位置为 ,则 。左端点在 之前的可以直接继承,在这之后的每一区间贡献都是 。
同理设 表示以 为左端点的所有区间最小值之和,求法类似。
考虑求答案时,求出区间最小值位置 ,跨过 的贡献为 。
考虑求 与 的贡献。比如求 ,设 ,考虑以 为左端点,且右端点 的贡献。可以发现贡献为 。因为每一个以 为左端点的区间,将左端点拓展到 ,最小值不变,而相减后剩余的就是 了。
同理, 可以用 算。维护 和 的前缀和,即可做到 的复杂度了。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <stack>
using namespace std;
const int N = 1e5 + 5;
int n, q, type;
long long a[N];
namespace gen
{
typedef unsigned long long ull;
ull s, a, b, c, lastans = 0;
ull rand()
{
return s ^= (a + b * lastans) % c;
}
};
int pre[N], suf[N];
long long f[N], revf[N];
long long s_f[N], s_revf[N];
int lson[N], rson[N];
int LG2[N];
int ff[N][21], p[N][21];
void Init()
{
memset(ff, 0x7f, sizeof ff);
for (int i = 2; i < N; i++) LG2[i] = LG2[i >> 1] + 1;
for (int i = 1; i <= n; i++) ff[i][0] = a[i], p[i][0] = i;
for (int j = 1; j <= LG2[n]; j++)
{
for (int i = 1; i + (1 << j) - 1 <= n; i++)
{
if (ff[i][j - 1] < ff[i + (1 << (j - 1))][j - 1])
{
ff[i][j] = ff[i][j - 1];
p[i][j] = p[i][j - 1];
}
else
{
ff[i][j] = ff[i + (1 << (j - 1))][j - 1];
p[i][j] = p[i + (1 << (j - 1))][j - 1];
}
}
}
}
int query(int l, int r)
{
int x = LG2[r - l + 1];
return (ff[l][x] < ff[r - (1 << x) + 1][x] ? p[l][x] : p[r - (1 << x) + 1][x]);
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> q >> type;
for (int i = 1; i <= n; i++) cin >> a[i], pre[i] = 0, suf[i] = n + 1;
if (type == 1) cin >> gen::s >> gen::a >> gen::b >> gen::c;
stack<int> st;
for (int i = 1; i <= n; i++)
{
while (st.size() && a[st.top()] > a[i])
{
lson[i] = st.top();
suf[st.top()] = i;
st.pop();
}
int p = (st.size() ? st.top() : 0);
pre[i] = p;
rson[p] = i;
st.push(i);
}
for (int i = 1; i <= n; i++)
{
f[i] = f[pre[i]] + (1LL * i - pre[i]) * a[i];
s_f[i] = s_f[i - 1] + f[i];
}
for (int i = n; i >= 1; i--)
{
revf[i] = revf[suf[i]] + (1LL * suf[i] - i) * a[i];
s_revf[i] = s_revf[i + 1] + revf[i];
}
Init();
unsigned long long res = 0;
while (q--)
{
int l, r;
if (type == 0) cin >> l >> r;
else
{
l = gen::rand() % n + 1, r = gen::rand() % n + 1;
}
if (l > r) swap(l, r);
int place = query(l, r);
long long ans = 0;
ans += 1ll * a[place] * (1ll * r - place + 1) * (1ll * place - l + 1);
ans += 1ll * (1ll * s_f[r] - s_f[place] - f[place] * 1ll * (1ll * r - place));
ans += 1ll * (1ll * s_revf[l] - s_revf[place] - revf[place] * (1ll * place - l));
gen::lastans = (unsigned long long)ans;
res ^= (unsigned long long)ans;
}
cout << res << "\n";
return 0;
}

浙公网安备 33010602011771号