跑步
考虑 (Theta(n^2)) 的暴力,(dp[i][j]=max(dp[i-1][j],dp[i][j-1])+a[i][j])
每次暴力做就有 (30'),考虑优化
随机数据下单点修改 (a[x][y]) 的时候有答案变化的点期望下并不多,可以直接 (bfs)
这样得到 (45')
正解是进一步的,考虑每次更改 (1) 对后继行和列的影响均为一个连续区间
且伴随距离的增大,区间位置的变化也是单调的
考虑对每行的 (dp) 数组差分,这样根据差分数组判断转移方向来进行基于原答案的修改即可
算术
长见识了,完全没想到
考虑 (k) 次剩余的式子,由费马小定理得到 (x^{p-1}equiv 1mod p)
设 (x=sqrt[k]{n}),选取若干个相关的 (p=ak+1),也就是满足 ((nmod p)^kequiv 1mod p)
那么选 (k+1dots 20k+1) 判断是不是素数然后快速幂
这样选择素数也是保证逆元的存在
求和
前置:卡常用具 (zkw) 线段树
先把树建成完全二叉树/满二叉树,考虑叶子节点上面的点数是 (bit=2^k-1)
那么每个叶子节点的标号可以快速计算
关于区间长度的操作要记区间长度,剩下的需要标记永久化
区间修改/查询的时候是两个叶子节点跳父亲,如果两个点的 (id_r-id_lle 1) 那就退
好像是不太复杂,不再赘
回到本题,考虑如果一个 (i) 满足 (jin[i-k,i+k],a_jle a_i) 都是要选的
维护每个点的权值,维护左/右边 (k) 个的最大权,再搞一个维护每个下标贡献的答案,单点修改,全局求 (max)
实现的时候维护左边是小于等于,右边是严格小于,不难证明是可以维护到所有的答案的
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define For(i,a,b) for(register int i=a;i<=b;++i)
#define Down(i,a,b) for(register int i=a;i>=b;i--)
#define reg register
inline int min(int x, int y) {
return x < y ? x : y;
}
inline int max(int x, int y) {
return x > y ? x : y;
}
inline void swap(int &x, int &y) {
int t = x;
x = y;
y = t;
return ;
}
namespace yspm {
inline int read() {
int res = 0, f = 1;
char k;
while (!isdigit(k = getchar()))
if (k == '-')
f = -1;
while (isdigit(k))
res = res * 10 + k - '0', k = getchar();
return res * f;
}
const int N = 3e6 + 10;
int n, a[N], pos[N], k, Q, typ, bit, val[N];
inline int cmp(int x, int y) {
return (a[x] ^ a[y]) ? (a[x] < a[y] ? y : x) : max(x, y);
}
inline void updpos(int x) {
for (x = (bit + x) >> 1; x; x >>= 1)
pos[x] = cmp(pos[x << 1], pos[x << 1 | 1]);
return ;
}
inline void updval(int x, int tv) {
val[x += bit] = tv;
for (; x != 1; x >>= 1)
val[x >> 1] = max(val[x], val[x ^ 1]);
return ;
}
inline int query(int l, int r) {
int ans = 0;
l += bit - 1, r += bit + 1;
for (; (r-l)!=1; l >>= 1, r >>= 1) {
if (!(l & 1))
ans = cmp(ans, pos[l ^ 1]);
if (r & 1)
ans = cmp(ans, pos[r ^ 1]);
}
return ans;
}
signed main() {
n = read(); k = read(); Q = read(); typ = read();
a[0] = -1; a[n + 1] = 1e18 + 10; bit = 1;
while (bit <= n) bit <<= 1;
for (reg int i = 1; i <= n; ++i)
val[i + bit] = a[i] = read(), pos[i + bit] = i;
for (reg int i = bit - 1; i; --i)
val[i] = max(val[i << 1], val[i << 1 | 1]), pos[i] = cmp(pos[i << 1], pos[i << 1 | 1]);
for (reg int i = 1, x, y; i <= n; ++i) {
x = query(max(1, i - k), i - 1);
y = query(i + 1, min(i + k, n));
if (a[x] <= a[i] && a[y] < a[i])
updval(i, a[i] + max(a[x], a[y]));
}
printf("%lld
", val[1]);
while (Q--) {
int x = read() ^ (val[1] * typ), y = read() ^ (val[1] * typ);
a[x] = y;
updpos(x);
y = query(max(1, x - k), x - 1);
int z = query(x + 1, min(x + k, n));
if (a[y] <= a[x] && a[z] < a[x])
updval(x, a[x] + max(a[z], a[y]));
else {
if (val[x + bit] > 0)
updval(x, 0);
int tx = y ? query(max(y - k, 1), y - 1) : n + 1, ty = a[tx] <= a[y] ? query(y + 1, min(y + k, n)) : n + 1;
if (a[ty] < a[y])
updval(y, a[y] + max(a[tx], a[ty]));
tx = z ? query(max(z - k, 1), z - 1) : n + 1;
ty = a[tx] <= a[z] ? query(z + 1, min(z + k, n)) : n + 1;
if (a[ty] < a[z])
updval(z, a[z] + max(a[tx], a[ty]));
}
printf("%lld
", val[1]);
}
return 0;
}
}
signed main() {
return yspm::main();
}