2021牛客多校7 - xay loves monotonicity(线段树区间合并)

Posted Frozen_Guardian

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021牛客多校7 - xay loves monotonicity(线段树区间合并)相关的知识,希望对你有一定的参考价值。

题目链接:点击查看

题目大意:给出一个长度为 n n n 的数字序列 a a a 01 01 01 序列 b b b,需要执行 m m m 次操作,每次操作分为如下三种类型:

  1. 1 x y:修改 a [ x ] = y a[x]=y a[x]=y
  2. 2 l r:区间 [ l , r ] [l,r] [l,r] 内的 b b b 置反
  3. 3 l r:输出区间 [ l , r ] [l,r] [l,r] 的贡献

最后说一下区间 [ l , r ] [l,r] [l,r] 的贡献为,首先找到区间 [ l , r ] [l,r] [l,r] 内的 “最长不下降子序列”,设其为 { p 1 , p 2 , . . . , p k } \\{p_1,p_2,...,p_k\\} {p1,p2,...,pk},需要满足:

  1. p 1 = l p_1=l p1=l
  2. a p 1 ≤ a p 2 ≤ a p 3 . . . a_{p_1}\\le a_{p_2} \\le a_{p_3}... ap1ap2ap3...
  3. 对于任意 j ∈ ( p i , p i + 1 ) j\\in(p_i,p_{i+1}) j(pi,pi+1),满足 a j < a i a_j<a_i aj<ai

然后将数组 b b b 中相应的 01 01 01 序列取出,即 { b p 1 , b p 2 , b p 3 , . . . , b p k } \\{b_{p_1},b_{p_2},b_{p_3},...,b_{p_k}\\} {bp1,bp2,bp3,...,bpk}

贡献就是 ∑ i = 1 k [ b i ≠ b i − 1 ] \\sum\\limits_{i=1}^{k}[b_i \\neq b_{i-1}] i=1k[bi=bi1]

题目分析:弱化版:HDU - 6406

其实这个题在思路上和弱化版没有区别,只是加了些许条件,只需要对 c a l cal cal 函数进行一下魔改就可以了

先回顾一下简单版本,如果只需要求解 “最长不下降子序列” 的个数,那么定义 c a l ( k , m x ) cal(k,mx) cal(k,mx) 为前一项为 m x mx mx ,线段树的节点 k k k 所提供的贡献。如何求解?线段树维护一下区间的最大值,分成两种情况讨论:

  1. 左子树的 m m a x mmax mmax 小于 m x mx mx:那么左子树没有贡献,只需要递归右子树返回 c a l ( k < < 1 ∣ 1 , m x ) cal(k<<1|1,mx) cal(k<<11,mx) 即可
  2. 左子树的 m m a x mmax mmax 大于等于 m x mx mx:左右子树都有可能有贡献,答案为 c a l ( k < < 1 , m x ) + c a l ( k < < 1 ∣ 1 , m x ) cal(k<<1,mx)+cal(k<<1|1,mx) cal(k<<1,mx)+cal(k<<11,mx)

这里为了方便追踪 m x mx mx 的状态,我们将其作为引用或者全局变量进行传值,因为在线段树中检索的顺序是先左后右,宏观来看就是从左向右扫描序列的过程,所以实时更新 m x mx mx 也就模拟了题目中的不断寻找 “最长不下降子序列” 的过程了。

然后就是我们发现上面的第二种情况的复杂度有点不乐观,但是我们不难看出,在递归完左子树后,右子树的答案就完全受左子树所影响了,而对于子树 k k k 来说,我们早就通过 p u s h u p pushup pushup 维护好答案了,所以可以 O ( 1 ) O(1) O(1) 计算右子树的贡献为 c n t [ k ] − c n t [ l c [ k ] ] cnt[k]-cnt[lc[k]] cnt[k]cnt[lc[k]]

所以就简单描述出了弱化版本的 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n) 的做法

回到本题我们该如何维护该序列映射到数组 b b b 上的贡献呢,其实只需要在 c a l cal cal 函数中额外维护一个参数就可以了: c a l ( k , m x , p r e ) cal(k,mx,pre) cal(k,mx,pre) 代表的是,前一项为 m x mx mx m x mx mx 所代表的位置的 b b b 的状态为 p r e pre pre,子树 k k k 所提供的贡献。在 c a l cal cal 递归到叶子节点时直接计算答案就好了

需要注意的是,在上述两种情况中的第二种情况,虽然优化了访问右子树的过程,但是返回的时候别忘了更新 m x mx mx p r e pre pre 为右子树结束时的状态(因为要从左到右扫描原序列)

剩下的两种操作无非就是单点修改和区间修改,中规中矩的线段树操作就不多说了

计算答案时的初始值根据题意设置成 a [ l ] a[l] a[l] b [ l ] b[l] b[l] 就可以了

代码:

// Problem: xay loves monotonicity
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/11258/B
// Memory Limit: 524288 MB
// Time Limit: 4000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// #pragma GCC optimize(2)
// #pragma GCC optimize("Ofast","inline","-ffast-math")
// #pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<list>
#include<unordered_map>
#define lowbit(x) (x&-x)
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
template<typename T>
inline void read(T &x)
{
	T f=1;x=0;
	char ch=getchar();
	while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	x*=f;
}
template<typename T>
inline void write(T x)
{
	if(x<0){x=~(x-1);putchar('-');}
    if(x>9)2021牛客多校7 - xay loves trees(dfs序+主席树-标记永久化)

牛客多校2021 F.xay loves trees(树状数组+树上的滑动窗口)

牛客多校7.F.xay loves trees 主席树+dfs序

2021牛客多校训练7 I xay loves or

2021牛客暑期多校训练营7 F.xay loves trees 主席树+dfs序

2021牛客多校7 Fxay loves trees