用户工具

站点工具


2020-2021:teams:legal_string:组队训练比赛记录:contest12

这是本文档旧的修订版!


比赛链接

补题情况

题目 蒋贤蒙 王赵安 王智彪
A 0 0 0
B 2 0 0
C 0 0 0
D 0 0 0
E 0 0 0
G 0 0 0
J 0 0 0
K 0 0 0

题解

B. xay loves monotonicity

题意

给定一个序列 $A$ 和序列 $B$,其中 $0\le b_i\le 1$ 接下来三种操作:

  1. $a_i\gets t$
  2. 对 $l\le i\le r$,$b_i\gets b_i\oplus 1$
  3. 给定 $l,r$。选取最长下标序列 $l\le i_1\le i_2\le \cdots i_k\le r$,满足 $a_{i_1}\le a_{i_2}\le\cdots \le a_{i_k}$,且对任意 $i_t\lt j\lt i_{t+1}$ 有 $a_j\lt a_{i_t}$。

对每个操作 $3$,输出 $b_{i_t}\neq b_{i_{t+1}}$ 的个数。

题解

设 $ma(L,R)=\max(a[L\sim R]),mb(L,R)$ 表示 $ma(L,R)$ 对应的 $b_i$,如果存在多个就取最右边的。

设 $\text{query}(L,R,p,q)$ 表示假如当前序列末尾对应 $a_i=p,b_i=q$ 时遍历区间 $(L,R)$ 得到的答案。

于是,如果 $a_i\gt ma(L,M)$,则 $\text{query}(L,R,p,q)=\text{query}(M+1,R,p,q)$。

否则,有 $\text{query}(L,R,p,q)=\text{query}(L,M,p,q)+\text{query}(M+1,R,ma(L,M),mb(L,M))$。

建立线段树,每个区间维护 $\text{query}(M+1,R,ma(L,M),mb(L,M))$。

这样,对一个询问,如果该询问正好对应一个线段树区间,则查询复杂度 $O(\log n)$。

否则,将该询问拆分成 $O(\log n)$ 个线段树区间,串联查询计算答案,时间复杂度 $O(\log^2 n)$。

对与修改操作,修改完暴力询问更新 $\text{query}(M+1,R,ma(L,M),mb(L,M))$,由于这是线段树区间,所以复杂度为 $O(\log n)$。

所以修改的总复杂度也是 $O\left(\log^2 n\right)$。总时间复杂度 $O\left(n\log n+q\log^2 n\right)$。

ps. 比赛写了 $O(nq)$ 的假算法,居然过了。

查看代码

查看代码

const int MAXN=2e5+5;
int a[MAXN],b[MAXN];
int lef[MAXN<<2],rig[MAXN<<2],s[MAXN<<2],tag[MAXN<<2];
struct Node{
	int a,b;
}mv[MAXN<<2];
Node Max(Node L,Node R){
	if(L.a>R.a)
	return L;
	else
	return R;
}
void push_tag(int k){
	mv[k].b^=1;
	tag[k]^=1;
}
void push_down(int k){
	if(tag[k]){
		push_tag(k<<1);
		push_tag(k<<1|1);
		tag[k]=0;
	}
}
int query(int k,int a,int b){
	if(lef[k]==rig[k])
	return mv[k].a>=a&&mv[k].b!=b;
	push_down(k);
	if(a<=mv[k<<1].a)
	return query(k<<1,a,b)+s[k];
	else
	return query(k<<1|1,a,b);
}
void push_up(int k){
	mv[k]=Max(mv[k<<1],mv[k<<1|1]);
	s[k]=query(k<<1|1,mv[k<<1].a,mv[k<<1].b);
}
void build(int k,int L,int R){
	lef[k]=L,rig[k]=R;
	int M=L+R>>1;
	if(L==R){
		mv[k]=Node{a[M],b[M]};
		return;
	}
	build(k<<1,L,M);
	build(k<<1|1,M+1,R);
	push_up(k);
}
Node query_max(int k,int L,int R){
	if(L<=lef[k]&&rig[k]<=R)
	return mv[k];
	push_down(k);
	int mid=lef[k]+rig[k]>>1;
	if(mid>=R)
	return query_max(k<<1,L,R);
	else if(mid<L)
	return query_max(k<<1|1,L,R);
	else
	return Max(query_max(k<<1,L,R),query_max(k<<1|1,L,R));
}
int query(int k,int L,int R,int a,int b){
	if(L<=lef[k]&&rig[k]<=R)
	return query(k,a,b);
	push_down(k);
	int mid=lef[k]+rig[k]>>1;
	if(mid>=R)
	return query(k<<1,L,R,a,b);
	else if(mid<L)
	return query(k<<1|1,L,R,a,b);
	else{
		Node t=query_max(k<<1,L,R);
		if(a<=t.a)
		return query(k<<1,L,R,a,b)+query(k<<1|1,L,R,t.a,t.b);
		else
		return query(k<<1|1,L,R,a,b);
	}
}
void update1(int k,int pos,int v){
	if(lef[k]==rig[k]){
		mv[k].a=v;
		return;
	}
	push_down(k);
	int mid=lef[k]+rig[k]>>1;
	if(mid>=pos)
	update1(k<<1,pos,v);
	else
	update1(k<<1|1,pos,v);
	push_up(k);
}
void update2(int k,int L,int R){
	if(L<=lef[k]&&rig[k]<=R){
		push_tag(k);
		return;
	}
	push_down(k);
	int mid=lef[k]+rig[k]>>1;
	if(mid>=L)
	update2(k<<1,L,R);
	if(mid<R)
	update2(k<<1|1,L,R);
	push_up(k);
}
int main(){
	int n=read_int();
	_rep(i,1,n)a[i]=read_int();
	_rep(i,1,n)b[i]=read_int();
	build(1,1,n);
	int q=read_int();
	while(q--){
		int opt=read_int(),t1=read_int(),t2=read_int();
		if(opt==1)
		update1(1,t1,t2);
		else if(opt==2)
		update2(1,t1,t2);
		else{
			if(t1==t2)
			enter(0);
			else{
				Node t=query_max(1,t1,t1);
				enter(query(1,t1+1,t2,t.a,t.b));
			}
		}
	}
	return 0;
}
2020-2021/teams/legal_string/组队训练比赛记录/contest12.1628424065.txt.gz · 最后更改: 2021/08/08 20:01 由 jxm2001