我们考虑分块。
我们设置一个 E ,表示我们要维护 E 个线段树。
第 i 个线段树按照这样的顺序维护元素:
于是对于每个 d≤E 的询问,我们就可以直接在第 d 个线段树里边求区间最大值。
对于 d>E 的询问,我们就暴力每次加 d 地一个一个更新最大值。
每次修改的复杂度是 O(Elogn) 的,
每次查询的复杂度是 O(logn) 或者 O(nE) 的。
我们考虑设置 E 的大小使得 Elogn+nE 最小。
根据基本不等式,可得:当 E=nlogn−−−−√ 的时候,
所以整个问题的时间复杂度就是 O(nn−−√logn) 的了。
然而理论上是这样,实际上令 E=min(nlogn−−−−√,10) 的时候效果最好。
(不信可以看我的提交记录。。。最快的那次就是这么设置的。。。)
毕竟 Gromah 太弱,只会做水题。
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define N 70000 + 5
#define S 100 + 5
#define M 262144 + 5
#define INF 0x7fffffff
#define ls(x) x << 1
#define rs(x) x << 1 | 1
int n, m, K, A[N], Tree[S + 1][M], Pos[S + 1][M];
inline void Modify(int k, int x, int l, int r, int t, int d)
{
if (l == r)
{
Tree[k][x] += d;
return ;
}
int mid = l + r >> 1;
if (t <= mid) Modify(k, ls(x), l, mid, t, d);
else Modify(k, rs(x), mid + 1, r, t, d);
Tree[k][x] = max(Tree[k][ls(x)], Tree[k][rs(x)]);
}
inline int Query(int k, int x, int l, int r, int s, int t)
{
if (l == s && r == t)
return Tree[k][x];
int mid = l + r >> 1;
if (t <= mid) return Query(k, ls(x), l, mid, s, t);
else if (s > mid) return Query(k, rs(x), mid + 1, r, s, t);
else return max(Query(k, ls(x), l, mid, s, mid), Query(k, rs(x), mid + 1, r, mid + 1, t));
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("3922.in", "r", stdin);
freopen("3922.out", "w", stdout);
#endif
scanf("%d", &n);
K = (int) sqrt((double) n / log2(n));
K = min(K, 10); //亲测这样子跑得最快。
for (int i = 1; i <= n; i ++)
scanf("%d", A + i);
for (int i = 1; i <= K; i ++)
{
int cnt = 0;
for (int j = 1; j <= i; j ++)
for (int k = 0; j + k * i <= n; k ++)
{
Pos[i][j + k * i] = ++ cnt;
Modify(i, 1, 1, n, cnt, A[j + k * i]);
}
}
scanf("%d", &m);
while (m --)
{
int op, u, v;
scanf("%d%d%d", &op, &u, &v);
if (op == 0)
{
for (int i = 1; i <= K; i ++)
Modify(i, 1, 1, n, Pos[i][u], v);
A[u] += v;
}
else if (op == 1)
{
if (v <= K)
{
int l = Pos[v][u], r = Pos[v][u + (n - u) / v * v];
int res = Query(v, 1, 1, n, l, r);
printf("%d\n", res);
}
else
{
int res = -INF;
for (; u <= n; u += v)
res = max(res, A[u]);
printf("%d\n", res);
}
}
}
#ifndef ONLINE_JUDGE
fclose(stdin);
fclose(stdout);
#endif
return 0;
}