洛谷 SP1557 / SPOJ GSS2 Can you answer these queries II

洛谷传送门

SPOJ 传送门

思路

看到去重想到离线。将所有询问按右端点升序排序。设 \(lst_i\)\(a_j = a_i\)\(j < i\) 的最大 \(j\),若不存在则 \(lst_i = 0\)\(b_j\) 表示 \(\sum\limits_{k=j}^i a_k\),当枚举到 \(i\) 时,将 \(j \in [lst_i + 1,i]\)\(b_j \gets b_j + a_i\),这样就实现了去重。然后处理所有以 \(i\) 为右端点的询问,设为 \([l,i]\),则答案为 \(b\) 数组 \([l,i]\)历史最大值。为什么是历史最大值?因为如果是当前最大值,那么就默认子段的右端点为 \(i\),不是最优的。

查询历史最大值,要维护 \(mx,tag,hmx,htag\)\(mx\) 表示当前最大值,\(tag\) 表示加的懒标记,\(hmx\) 表示历史最大值,\(htag\) 表示历史 \(tag\) 的最大值。pushdown 时就是这样:

void pushdown(int x) {
	if (tree[x].htag) {
		tree[x << 1].hmx = max(tree[x << 1].hmx, tree[x << 1].mx + tree[x].htag);
		tree[x << 1 | 1].hmx = max(tree[x << 1 | 1].hmx, tree[x << 1 | 1].mx + tree[x].htag);
		tree[x << 1].htag = max(tree[x << 1].htag, tree[x << 1].tag + tree[x].htag);
		tree[x << 1 | 1].htag = max(tree[x << 1 | 1].htag, tree[x << 1 | 1].tag + tree[x].htag);
		tree[x].htag = 0;
	}
	if (tree[x].tag) {
		tree[x << 1].mx += tree[x].tag;
		tree[x << 1 | 1].mx += tree[x].tag;
		tree[x << 1].tag += tree[x].tag;
		tree[x << 1 | 1].tag += tree[x].tag;
		tree[x].tag = 0;
	}
}

其他细节见代码。

代码

code
/*

p_b_p_b txdy
AThousandMoon txdy
AThousandSuns txdy
hxy txdy

*/

#include <bits/stdc++.h>
#define pb push_back
#define fst first
#define scd second

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;

const int maxn = 100100;

ll n, m, a[maxn], ans[maxn], lst[maxn], pre[maxn << 1];
vector<pii> qq[maxn];

struct node {
	ll tag, mx, htag, hmx;
} tree[maxn << 2];

void pushup(int x) {
	tree[x].mx = max(tree[x << 1].mx, tree[x << 1 | 1].mx);
	tree[x].hmx = max(tree[x << 1].hmx, tree[x << 1 | 1].hmx);
}

void pushdown(int x) {
	if (tree[x].htag) {
		tree[x << 1].hmx = max(tree[x << 1].hmx, tree[x << 1].mx + tree[x].htag);
		tree[x << 1 | 1].hmx = max(tree[x << 1 | 1].hmx, tree[x << 1 | 1].mx + tree[x].htag);
		tree[x << 1].htag = max(tree[x << 1].htag, tree[x << 1].tag + tree[x].htag);
		tree[x << 1 | 1].htag = max(tree[x << 1 | 1].htag, tree[x << 1 | 1].tag + tree[x].htag);
		tree[x].htag = 0;
	}
	if (tree[x].tag) {
		tree[x << 1].mx += tree[x].tag;
		tree[x << 1 | 1].mx += tree[x].tag;
		tree[x << 1].tag += tree[x].tag;
		tree[x << 1 | 1].tag += tree[x].tag;
		tree[x].tag = 0;
	}
}

void update(int rt, int l, int r, int ql, int qr, ll x) {
	if (ql <= l && r <= qr) {
		tree[rt].mx += x;
		tree[rt].tag += x;
		tree[rt].hmx = max(tree[rt].hmx, tree[rt].mx);
		tree[rt].htag = max(tree[rt].htag, tree[rt].tag);
		return;
	}
	pushdown(rt);
	int mid = (l + r) >> 1;
	if (ql <= mid) {
		update(rt << 1, l, mid, ql, qr, x);
	}
	if (qr > mid) {
		update(rt << 1 | 1, mid + 1, r, ql, qr, x);
	}
	pushup(rt);
}

ll query(int rt, int l, int r, int ql, int qr) {
	if (ql <= l && r <= qr) {
		return tree[rt].hmx;
	}
	pushdown(rt);
	int mid = (l + r) >> 1;
	ll res = 0;
	if (ql <= mid) {
		res = max(res, query(rt << 1, l, mid, ql, qr));
	}
	if (qr > mid) {
		res = max(res, query(rt << 1 | 1, mid + 1, r, ql, qr));
	}
	return res;
}

void solve() {
	scanf("%lld", &n);
	for (int i = 1; i <= n; ++i) {
		scanf("%lld", &a[i]);
		lst[i] = pre[a[i] + maxn];
		pre[a[i] + maxn] = i;
	}
	scanf("%lld", &m);
	for (int i = 1; i <= m; ++i) {
		int l, r;
		scanf("%d%d", &l, &r);
		qq[r].pb(make_pair(l, i));
	}
	for (int i = 1; i <= n; ++i) {
		update(1, 1, n, lst[i] + 1, i, a[i]);
		for (pii p : qq[i]) {
			ans[p.scd] = query(1, 1, n, p.fst, i);
		}
	}
	for (int i = 1; i <= m; ++i) {
		printf("%lld\n", ans[i]);
	}
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}
posted @ 2022-06-26 13:04  zltzlt  阅读(20)  评论(0编辑  收藏  举报