P6604 [HNOI2016]序列 加强版

*I. P6604 [HNOI2016]序列 加强版

摘自学习笔记 简单树论 笛卡尔树部分例题 I.

P6503 比较类似。我们设 (f_i) 表示全局以 (i) 结尾的子区间的最小值之和,令 (p_i) 为下标在 (i) 之前第一个比 (a_i) 小的位置,显然有 (f_i=f_{p_i}+(i-p_i)a_i):因为 (a_i)(p_i) 以及 (p_i) 以前的最小值没有影响(即 ([1,p_i])([1,i])([2,p_i])([2,i]cdots) ([p_i,p_i])([p_i,i]) 的最小值相同),所以可以直接由 (f_{p_i}) 转移得来。而根据 (p_i) 的定义,后面 (i-p_i) 个子序列(即 ([p_i+1,i],[p_i+2,i]cdots,[i,i]))的最小值为 (a_i)

注意到 (p_i) 实际相当于 (i) 在笛卡尔树上第一个向左走的父亲,求 (p_i) 的过程十分类似构建笛卡尔树:笛卡尔树上每个节点的祖先由左右两个单调栈构成

考虑对一个区间求答案:求出区间最小值的位置 (p),那么左端在 (p) 左边,右端在 (p) 右边的子区间最小值为 (a_p),故答案加上 (a_p imes (p-l+1) imes (r-p+1))。此外,我们还需求出 ([l,p))((p,r]) 的答案:考虑 ((p,r]) 每个位置对答案的贡献都是 (f_r-f_p),因为 ([i,p])([i,r] (1leq ileq p)) 的最小值相同。前缀和优化可以做到 (mathcal{O}(1)) 回答每个询问。对于 ([l,p)) 同理,我们只需预处理出 (g_i) 表示全局以 (i) 开头的子区间的最小值之和并类似处理即可。

复杂度瓶颈在于区间 RMQ,时间复杂度 (mathcal{O}(nlog n+q))

const int N = 1e5 + 5;
const int K = 17;

namespace gen {
	ull s, a, b, c, las = 0;
	ull rand() {return s ^= (a + b * las) % c;}
}

int n, q, type, stc[N], *top = stc, a[N], lg[N], pre[N], suf[N];
ll mi[K][N], fp[N], gp[N], fs[N], gs[N]; ull res;
int cmp(int x, int y) {return a[x] < a[y] ? x : y;}
int RMQ(int l, int r) {int d = lg[r - l + 1]; return cmp(mi[d][l], mi[d][r - (1 << d) + 1]);}

int main(){
	cin >> n >> q >> type;
	for(int i = 1; i <= n; i++) a[i] = read(), mi[0][i] = i;
	for(int i = 2; i <= n; i++) lg[i] = lg[i >> 1] + 1;
	for(int i = 1; i <= lg[n]; i++)
		for(int j = 1; j + (1 << i) - 1 <= n; j++)
			mi[i][j] = cmp(mi[i - 1][j], mi[i - 1][j + (1 << i - 1)]);
	for(int i = 1; i <= n; i++) { 
		while(*top && a[*top] >= a[i]) suf[*top--] = i; // 可以类比求笛卡尔树的过程: ls[i] = *top, 因此 suf[*top] = i;
		pre[i] = *top, *++top = i; // 同理, rs[*top] = i, 所以 pre[i] = *top: 笛卡尔树上每个节点的祖先是由两个单调栈构成的!
	}
	for(int i = 1; i <= n; i++)
		fp[i] = fp[pre[i]] + 1ll * a[i] * (i - pre[i]), gp[i] = gp[i - 1] + fp[i];
	for(int i = n; i; i--)
		fs[i] = fs[suf[i]] + 1ll * a[i] * (suf[i] - i), gs[i] = gs[i + 1] + fs[i];
	if(type) gen :: s = read(), gen :: a = read(), gen :: b = read(), gen :: c = read();
	for(int i = 1, l, r; i <= q; i++) {
		if(type == 0) l = read(), r = read();
		else {
			l = gen :: rand() % n + 1;
			r = gen :: rand() % n + 1;
			if(l > r) swap(l, r);
		}
		ll p = RMQ(l, r), ans;
		ans = a[p] * (r - p + 1) * (p - l + 1);
		ans += gp[r] - gp[p] - fp[p] * (r - p);
		ans += gs[l] - gs[p] - fs[p] * (p - l);
		res ^= gen :: las = ans;
	}
	cout << res << endl;
    return flush(), 0;
}
原文地址:https://www.cnblogs.com/alex-wei/p/P6604_sequence.html