NOIP模拟试题详讲2021/11/4

又是爆0的一天呢
码风有点点变,可能以后都是这样了qwq

T1

题目大意:有2个序列A,B,可以使某区间加上一个数,每次修改询问 m i n ( m a x ( a 1 , a 2 , a 3 . . . a p , b p + 1 . . . b n ) ∣ 0 ≤ p ≤ n ) min(max(a_1,a_2,a_3...a_p,b_{p+1}...b_n)|0 \leq p\leq n) min(max(a1,a2,a3...ap,bp+1...bn)0pn)

思路:

我们发现:遍历的顺序是先走A,再走B。
情况1:
在这里插入图片描述

红色的代表 [ l , r ] [l,r] [l,r]区间的最大值,
我们发现如图,若A的最大值在B的最大值得前面,那么无论怎么走,必定要至少经过一个最大值,而题目要求我们求整个区间的最大值的最小值。
那么对于这种情况最小值就是A,B最大值的较小的一个。
情况2:
如果A的最大值在B的最大值的后面。我们发现不好办了。
在这里插入图片描述

我们发现L到B的最大值的区域是都要走的,A的最大值到R的区域也是都要走的。
所以我们查询这2段区间的最大值,当然A的最大值,B的最大值也要走,所以还要比较一下A和B的最大值的最小值,对于中间的部分,我们不知道怎么走。
我们可以使用分治思想,重复以上步骤,不断的缩小范围,最后便可得到最后的解。
**核心代码:**注释的部分与下面的是等价的,但下面的更好理解

int solve(int l,int r){
    
    
	if(l>r) return -inf;
	node ma=A.query(1,l,r);
	node mb=B.query(1,l,r);
	if(ma.pos<=mb.pos) return min(ma.mx,mb.mx);
	else{
    
    
		//if(ma.mx<=mb.mx) return max(A.query(1,l,mb.pos).mx,solve(mb.pos+1,r));
		//else return max(B.query(1,ma.pos,r).mx,solve(l,ma.pos-1));
		return min(min(ma.mx,mb.mx),max(solve(mb.pos+1,ma.pos-1),max(A.query(1,l,mb.pos).mx,B.query(1,ma.pos,r).mx)));
	}
}

对于区间加,我们可以用线段树更新,并且正好也维护区间的最大值,这样问题就解决了。对于线段树封装了一下,其实也差不多,但可以少用一些数组。
代码:

#include<bits/stdc++.h>
using namespace std;
#define lc k<<1
#define rc k<<1|1 
//#pragma GCC optimize(2)

#define num ch-'0'
void get(int &res)
{
    
    
    char ch;bool flag=0;
    while(!isdigit(ch=getchar()))
        (ch=='-')&&(flag=true);
    for(res=num;isdigit(ch=getchar());res=res*10+num);
    (flag)&&(res=-res);
}

const int N=6e5+5,inf=0x3f3f3f3f;
int n,m,a[N],b[N];
struct node{
    
    
	int mx,pos;
};
struct TREE{
    
    
	struct nde{
    
    
		int l,r,mx,pos,lz;
	}t[N<<2];
	void pushup(int k){
    
    
		if(t[lc].mx>=t[rc].mx){
    
    
			t[k].mx=t[lc].mx;
			t[k].pos=t[lc].pos;
		}
		else{
    
    
			t[k].mx=t[rc].mx;
			t[k].pos=t[rc].pos;
		}
	}
	void pushdown(int k){
    
    
		if(t[k].lz){
    
    
			t[lc].mx+=t[k].lz;
			t[rc].mx+=t[k].lz;
			t[lc].lz+=t[k].lz;
			t[rc].lz+=t[k].lz;
			t[k].lz=0;
		}
	}
	void build(int k,int l,int r,int cas){
    
    
		t[k].l=l,t[k].r=r;
		if(l==r){
    
    
			if(cas==1) t[k].mx=a[l];
			else t[k].mx=b[l];
			t[k].pos=l;
			t[k].lz=0;
			return;
		}
		int mid=(l+r)>>1;
		build(lc,l,mid,cas);
		build(rc,mid+1,r,cas);
		pushup(k);
	}
	void update(int k,int l,int r,int val){
    
    
		if(t[k].l>=l && t[k].r<=r){
    
    
			t[k].lz+=val;
			t[k].mx+=val;
			return;
		}
		pushdown(k);
		int mid=(t[k].l+t[k].r)>>1;
		if(l<=mid) update(lc,l,r,val);
		if(r>mid) update(rc,l,r,val);
		pushup(k);
	}
	node query(int k,int l,int r){
    
    
		if(t[k].l>=l && t[k].r<=r) return (node){
    
    t[k].mx,t[k].pos};
		pushdown(k);
		int mid=(t[k].l+t[k].r)>>1;
		node res,now;res.mx=-inf;
		if(l<=mid){
    
    
			now=query(lc,l,r);
			if(res.mx<now.mx){
    
    
				res.mx=now.mx;
				res.pos=now.pos;
			}
		} 
		if(r>mid){
    
    
			now=query(rc,l,r);
			if(res.mx<now.mx){
    
    
				res.mx=now.mx;
				res.pos=now.pos;
			}
		} 
		return res;
	}
}A,B;

int solve(int l,int r){
    
    
	if(l>r) return -inf;
	node ma=A.query(1,l,r);
	node mb=B.query(1,l,r);
	if(ma.pos<=mb.pos) return min(ma.mx,mb.mx);
	else{
    
    
		//if(ma.mx<=mb.mx) return max(A.query(1,l,mb.pos).mx,solve(mb.pos+1,r));
		//else return max(B.query(1,ma.pos,r).mx,solve(l,ma.pos-1));
		return min(min(ma.mx,mb.mx),max(solve(mb.pos+1,ma.pos-1),max(A.query(1,l,mb.pos).mx,B.query(1,ma.pos,r).mx)));
	}
}

int main(){
    
    
	//freopen("girl.in","r",stdin);
	//freopen("girl.out","w",stdout);
	get(n);get(m);
	for(int i=1;i<=n;i++) get(a[i]);
	for(int i=1;i<=n;i++) get(b[i]);
	A.build(1,1,n,1);B.build(1,1,n,2);
	char str;int l,r,k;
	for(int i=1;i<=m;i++){
    
    
		cin>>str;
		get(l);get(r);get(k);
		if(str=='A') A.update(1,l,r,k);
		else B.update(1,l,r,k);
		get(l);get(r);
		cout<<solve(l,r)<<endl;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/pigonered/article/details/121151311