题解:P8539 「Wdoi-2」来自地上的支援
deepthinker · · 题解
P8539 「Wdoi-2」来自地上的支援题解
省流:线段树好题(好像可以
题面传送门
题目大意
有
算法思路
观察
因为第
数学推导
对于位置
- 对于前面的要求:
s 必须 ≥ 前x-1 次操作后的最大值pre_x - 在区间里的要求:对于
j \in [x+1, x+k-1] ,需要满足:s + (j - x) \times v > a_j
线段树优化
使用线段树维护
对于所有
代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 2000010;
int n, m, v;
int a[N];
ll pre[N], ans1, ans2;
ll tr[4 * N];//线段树
void build(int u, int l, int r)
{
if (l == r)
{
tr[u] = a[l] - (ll)l * v;
return;
}
int mid = (l + r) >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
tr[u] = max(tr[u << 1], tr[u << 1 | 1]);
}
ll query(int u, int l, int r, int L, int R)
{
if (L > R)
return -1e18;
if (L <= l && r <= R)
return tr[u];
int mid = (l + r) >> 1;
ll res = -1e18;
if (L <= mid)
res = max(res, query(u << 1, l, mid, L, R));
if (R > mid)
res = max(res, query(u << 1 | 1, mid + 1, r, L, R));
return res;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> m >> v;
for (int i = 1; i <= n; i++)
cin >> a[i];
build(1, 1, n);//构建线段树
ll cur = 0;//预处理最大值
for (int i = 1; i <= n; i++)
{
pre[i] = cur;
if (a[i] > cur)
cur = a[i];
cur += v;
}
while (m--)
{
int x, k;
cin >> x >> k;
if (x + k - 1 > n)//无法选择k次
{
continue;
}
ll s = pre[x];
if (k > 1)
{
// 查询区间 [x+1, x+k-1] 的最大值
ll qval = query(1, 1, n, x + 1, x + k - 1);
s = max(s, qval + (ll)x * v + 1);
}
ans1 ^= s;
ans2 += s;//统计答案
}
cout << ans1 << " " << ans2;
return 0;
}
完结撒花~~