题解:P14638 [NOIP2025] 序列询问 / query
lovely_nst · · 题解
[NOIP2025] 序列询问 / query
题意简述
每次询问
其中
正文
设点
先看
加上
即要对于每个
右侧(平行四边形)
因为初始两条线(图一)不会变,因此可以对于每个
左侧(三角形)
如图,将三角形沿中点切割成一个正方形(绿)和两个三角形。
因为只是求
预处理 ST 表时间复杂度
细节
- “小于”的细节要处理好。
- 当左侧三角形边上的点数为奇数时无法均分,但是可以调整三角形与右侧的共边使其可以均分。
- 注意初始化。
- 需要略微卡常,双端队列建议手写。
AC Code
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5 + 5 , M = 15;
const ll inf = 2e18 + 7;
struct Deque
{
int a[N] , head , tail;
inline void init ()
{head = 1 , tail = 0;}
inline void push (int x)
{a[++ tail] = x;}
inline void pop_front () {head ++;}
inline void pop_back () {tail --;}
inline int front () {return a[head];}
inline int back () {return a[tail];}
inline bool empty () {return head == tail + 1;}
} qu;
int n , q;
ll a[N] , w[N] , wl[N] , wr[N] , ans[N] , f[M + 1][N] , g[M + 1][N];
int lg[N];
inline void init ()
{
lg[0] = -1;
for (int i = 1;i <= n;i ++) lg[i] = lg[i >> 1] + 1;
for (int i = 0;i <= n;i ++) f[0][i] = -a[i] , g[0][i] = a[i];
for (int j = 1;j <= M;j ++)
for (int i = 0;i + (1 << j) - 1 <= n;i ++)
f[j][i] = max (f[j - 1][i] , f[j - 1][i + (1 << j - 1)]),
g[j][i] = max (g[j - 1][i] , g[j - 1][i + (1 << j - 1)]);
}
inline ll Maxf (int l , int r)
{
if (r < l) return -inf;
l = max (l , 0);
int Log = lg[r - l + 1];
return max (f[Log][l] , f[Log][r - (1 << Log) + 1]);
}
inline ll Maxg (int l , int r)
{
if (r < l) return -inf;
r = min (r , n);
int Log = lg[r - l + 1];
return max (g[Log][l] , g[Log][r - (1 << Log) + 1]);
}
inline void solve (int L , int R)
{
for (register int i = 0;i <= n;++ i)
w[i] = wl[i] = wr[i] = -inf;
int m = n - L;
for (register int i = 0;i <= m;++ i)
w[i] = Maxg (i + L , i + R) - a[i];
qu.init ();
for (register int i = 1;i <= n;++ i)
{
while (!qu.empty () && qu.front () < i - L) qu.pop_front ();
while (!qu.empty () && w[qu.back ()] <= w[i - 1]) qu.pop_back ();
qu.push (i - 1);
ans[i] = w[qu.front ()];
}
int sz = R - L + 1;
if (sz & 1) sz ++;
sz >>= 1;
m = n - L - sz;
for (register int i = 0;i <= m;++ i)
wl[i] = Maxg (i + L + sz , i + R) - a[i];
qu.init ();
for (register int i = L;i <= n;++ i)
{
int p = i - L - sz , q = i - L;
while (!qu.empty () && qu.front () <= p) qu.pop_front ();
while (!qu.empty () && wl[qu.back ()] <= wl[q]) qu.pop_back ();
qu.push (q);
if (!qu.empty ()) ans[i] = max (ans[i] , wl[qu.front ()]);
}
for (register int i = L + sz;i <= n;++ i)
wr[i] = a[i] + Maxf (i - R , i - L - sz);
qu.init ();
for (register int i = L + 1;i <= n;++ i)
{
int q = i + sz - 1;
while (!qu.empty () && qu.front () < i) qu.pop_front ();
if (n >= q)
{
while (!qu.empty () && wr[qu.back ()] <= wr[q]) qu.pop_back ();
qu.push (q);
}
if (!qu.empty ()) ans[i] = max (ans[i] , wr[qu.front ()]);
}
for (register int i = L;i <= n;++ i)
ans[i] = max (Maxg (i , i + sz - 1) + Maxf (i - L - sz + 1 , i - L) , ans[i]);
unsigned ll ANS = 0;
for (register int i = 1;i <= n;++ i)
ANS ^= ans[i] * i;
cout << ANS << '\n';
}
signed main ()
{
ios::sync_with_stdio (0);
cin.tie (0) , cout.tie (0);
cin >> n;
for (register int i = 1;i <= n;i ++) cin >> a[i] , a[i] += a[i - 1];
init ();
cin >> q;
while (q --)
{
int L , R;
cin >> L >> R;
solve (L , R);
}
return 0;
}