2021牛客暑期多校训练营7 部分题题解
Posted Alkaid~
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021牛客暑期多校训练营7 部分题题解相关的知识,希望对你有一定的参考价值。
B.xay loves monotonicity
题目链接
简要题解
不难看出这是一道维护序列信息的数据结构题。
我们需要支持单点修改\\(A\\)序列,区间修改\\(B\\)序列,以及区间查询一个特殊的值。
具体地说,对于一个询问,我们要取出序列\\(A\\)在这个区间内,包含左端点的最长不降子序列,并把子序列的位置对应到序列\\(B\\)中得到一个\\(0/1\\)串。
我们需要求这个\\(0/1\\)串中有多少个值不同的相邻对。
这可以说是一个经典题,应该也可以说是一个套路题。
如果我们要在一个区间内求一个最长不降子序列,那么这个区间内的最大值一定在子序列中,并且这个最大值一定在序列末尾。
基于这个性质,两个区间的信息就可以合并,而线段树很适合维护多个区间合并的信息。
我们在线段树上维护区间内\\(A\\)序列的最大值,以及这个最大值所在位置对应的\\(B\\),若有多个最大值则维护最右边的那一个。
我们需要解决的问题可以用一个\\(Calc(l,r,a,b)\\)来描述:如果当前序列末尾的数为\\(a\\),其对应的\\(B\\)值为\\(b\\),那么\\([l,r]\\)这段区间可以提供多少贡献。
很明显,加上这段区间后,序列的末尾,要么是这段区间的最大值,要么是原来的\\(a\\),于是我们可以接着往后面合并区间。
线段树可以将一个询问区间分成\\(logn\\)个线段树节点维护的区间,我们已经知道如何合并区间,现在只需要对每个区间快速计算\\(Calc(l,r,a,b)\\)。
对于线段树节点维护的一个区间来说,如果左边\\(A\\)序列的最大值小于\\(a\\),那么左边就没有贡献,直接递归右边。
否则,合并左半边区间后,不降子序列的末尾就是左半边序列的最大值,设为\\(a_l\\)。
而我们已经知道\\(a_l\\)以及对应的\\(b_l\\),只要提前算出右半边区间的\\(Calc(l,r,a_l,b_l)\\),记为\\(C\\),就可以直接加上贡献,只递归左边。
我们从下往上维护每个区间的\\(C\\),每次维护需要\\(logn\\)的递归计算,因此总复杂度是\\(O(nlog^2n)\\)的。
因此,我们需要在线段树上维护三个值:\\(A\\)序列的区间最大值\\(a\\),\\(a\\)在\\(B\\)序列对应位置的值\\(b\\),当左区间最大值作为子序列末尾时右区间的\\(C\\)值。
对于\\(A\\)序列和\\(B\\)序列的修改,就是单点修改与区间修改,修改完及时\\(Push\\_up\\)维护\\(C\\)值即可。
对于一个区间的询问,在线段树上可以拆成\\(logn\\)个区间,依次对每个区间调用\\(Calc\\)函数,再合并即可。
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int MAXN=2e5+10;
int n,Qs,A[MAXN],B[MAXN];
int Read()
{ int a=0,c=1; char b=getchar();
while(b!=\'-\'&&(b<\'0\'||b>\'9\')) b=getchar();
if(b==\'-\') c=-1,b=getchar();
while(b>=\'0\'&&b<=\'9\') a=a*10+b-48,b=getchar();
return a*c;
}
int Max(int A,int B){ return A>B?A:B; }
namespace TREE
{ struct ELE{ int Mv,Ma,Mb; };
int Maxa[MAXN*4],Maxl[MAXN*4];
bool Maxb[MAXN*4],Lan[MAXN*4];
ELE operator + (ELE A,ELE B)
{ if(B.Ma>=A.Ma) return (ELE){A.Mv+B.Mv,B.Ma,B.Mb};
return (ELE){A.Mv+B.Mv,A.Ma,A.Mb};
}
void Push_down(int S)
{ if(!Lan[S]) return;
Maxb[S<<1]^=1,Lan[S<<1]^=1,Maxb[S<<1|1]^=1,Lan[S<<1|1]^=1,Lan[S]=0;
}
int Calc(int S,int Le,int Ri,int Num,int Nb,int Mid=0)
{ if(Le==Ri) return Maxa[S]>=Num?Maxb[S]!=Nb:0;
Mid=(Le+Ri)>>1,Push_down(S);
return Maxa[S<<1]>=Num?Calc(S<<1,Le,Mid,Num,Nb)+Maxl[S]:Calc(S<<1|1,Mid+1,Ri,Num,Nb);
}
void Push_up(int S,int Le,int Ri,int Mid=0)
{ if(Maxa[S<<1|1]<Maxa[S<<1]) Maxa[S]=Maxa[S<<1],Maxb[S]=Maxb[S<<1];
else Maxa[S]=Maxa[S<<1|1],Maxb[S]=Maxb[S<<1|1];
Mid=(Le+Ri)/2,Maxl[S]=Calc(S<<1|1,Mid+1,Ri,Maxa[S<<1],Maxb[S<<1]);
}
void Build(int S,int Le,int Ri,int Mid=0)
{ if(Le==Ri) return Maxa[S]=A[Le],Maxb[S]=B[Le],(void)0;
Mid=(Le+Ri)>>1,Build(S<<1,Le,Mid),Build(S<<1|1,Mid+1,Ri),Push_up(S,Le,Ri);
}
void Modify1(int S,int Le,int Ri,int Aim,int Num,int Mid=0)
{ if(Le==Ri) return Maxa[S]=Num,(void)0;
Mid=(Le+Ri)>>1,Push_down(S);
Aim<=Mid?Modify1(S<<1,Le,Mid,Aim,Num):Modify1(S<<1|1,Mid+1,Ri,Aim,Num),Push_up(S,Le,Ri);
}
void Modify2(int S,int Le,int Ri,int Al,int Ar,int Mid=0)
{ if(Al<=Le&&Ri<=Ar) return Lan[S]^=1,Maxb[S]^=1,(void)0;
Mid=(Le+Ri)/2,Push_down(S);
if(Al<=Mid) Modify2(S<<1,Le,Mid,Al,Ar),Push_up(S,Le,Ri);
if(Mid<Ar) Modify2(S<<1|1,Mid+1,Ri,Al,Ar),Push_up(S,Le,Ri);
Push_up(S,Le,Ri);
}
ELE Query(int S,int Le,int Ri,int Al,int Ar,int Num,int Nb,int Mid=0)
{ if(Al<=Le&&Ri<=Ar)
{ if(Maxa[S]<Num) return (ELE){0,Num,Nb};
return (ELE){Calc(S,Le,Ri,Num,Nb),Maxa[S],Maxb[S]};
}
Mid=(Le+Ri)>>1,Push_down(S);
ELE Ra=(ELE){0,Num,Nb},Rb=(ELE){0,Num,Nb};
if(Al<=Mid) Ra=Query(S<<1,Le,Mid,Al,Ar,Num,Nb);
if(Mid<Ar) Rb=Query(S<<1|1,Mid+1,Ri,Al,Ar,Ra.Ma,Ra.Mb);
return Ra+Rb;
}
int Query2(int S,int Le,int Ri,int Aim,int Mid=0)
{ if(Le==Ri) return Maxb[S];
return Push_down(S),Mid=(Le+Ri)/2,Aim<=Mid?Query2(S<<1,Le,Mid,Aim):Query2(S<<1|1,Mid+1,Ri,Aim);
}
}using namespace TREE;
int main()
{ n=Read();
for(int i=1;i<=n;i++) A[i]=Read();
for(int i=1;i<=n;i++) B[i]=Read();
Build(1,1,n),Qs=Read();
for(int i=1,K,T1,T2;i<=Qs;i++)
{ K=Read(),T1=Read(),T2=Read();
if(K==1) Modify1(1,1,n,T1,T2),A[T1]=T2;
if(K==2) Modify2(1,1,n,T1,T2);
if(K==3) printf("%d\\n",Query(1,1,n,T1,T2,A[T1],Query2(1,1,n,T1)).Mv);
}
}
以上是关于2021牛客暑期多校训练营7 部分题题解的主要内容,如果未能解决你的问题,请参考以下文章
2021牛客暑期多校训练营1 - F - Find 3-friendly Integers - 题解
2021牛客暑期多校训练营1 - F - Find 3-friendly Integers - 题解