20211104NOIP模拟赛

上一次考到了135分(还挂了60分),这次就直接0分啦~~QWQ

没关系,NOIP好好干!!(放屁!看错题了导致一分没有!区间最大值我以为是前缀积!)

第一题:
由于我只会第一题所以我好好讲一下。

算法一: 玄学二分答案l,在二分时线段树查询变成O(nlog2n)的时间复杂度。

期望得分:75~100(必须吸氧!!还要卡常)。

放代码

点击查看代码
#include<bits/stdc++.h>
#define in read()
#define MAXN 2000006
// #define int long long
using namespace std;
const int INF=1.6e9;
namespace IO{//忽略又臭又长的快读
    char buf[2000010],*cur=buf+2000010;
    inline char getc(){
        (cur==buf+2000010)?fread(cur=buf,1,2000010,stdin):0;
        return *cur++;
    }
    char buff[2000010],*curr=buff;
    inline void flush(){
        fwrite(buff,1,curr-buff,stdout);
    }
    inline void putc(const char &ch){
        (curr==buff+2000010)?fwrite(curr=buff,1,2000010,stdout):0;
        *curr++=ch;
    }
  
    inline void rd(int &x){
        x=0;char ch=getc();int f=1;
        while(ch<'0'||ch>'9'){
            if(ch=='-')f=-1;
            ch=getc();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+ch-'0';
            ch=getc();
        }
        x*=f;
    }
 
    char st[60];int tp;
    void PT(int x){
    	if(x<0)putc('-'),x=-x;
        if(x==0)putc('0');
        else{
            while(x>0){
                st[++tp]=x%10+'0';
                x/=10;
            }
        }
        while(tp)putc(st[tp--]);
    }
}
using IO::getc;
using IO::putc;
using IO::rd;
using IO::PT;
int n,m,lask,rask,ladd,radd,addnum,maxnum=-INF,minnum=INF;
int treev[MAXN][2],treel[MAXN][2];//一个是max一个是tag
inline void down(int k,int id)
{
	treel[(k<<1)][id]+=treel[k][id],treel[k<<1|1][id]+=treel[k][id];
	treev[k<<1][id]+=treel[k][id],treev[k<<1|1][id]+=treel[k][id];
	treel[k][id]=0;
}

inline void add(int k,int id,int L,int R)
{
	if(L>=ladd&&R<=radd)
	{
		treev[k][id]+=addnum;
		treel[k][id]+=addnum;
		maxnum=max(maxnum,treev[k][id]),minnum=min(minnum,treev[k][id]);
//		cerr<<"Tree:"<<id<<" id:"<<k<<" L:"<<L<<" R:"<<R<<" v:"<<treev[k][id]<<'\n';
		return;
	}
	if(treel[k][id]) down(k,id);
	int mid=(L+R)>>1;
	if(ladd<=mid) add((k<<1),id,L,mid);
	if(radd>mid) add((k<<1)+1,id,mid+1,R);
	treev[k][id]=max(treev[k<<1][id],treev[k<<1|1][id]);
//	cerr<<"Tree:"<<id<<" id:"<<k<<" L:"<<L<<" R:"<<R<<" v:"<<treev[k][id]<<'\n';
}

int l,r,ans;
inline int findA(int mid,int pos,int L,int R)//寻找mid在A中的位置
{
	if(l<=L&&R<=r)
	{
		if(treev[pos][0]<=mid) return R;
		if(L==R) return L-1;
		down(pos,0);
		int mmm=(L+R)>>1;
		if(treev[pos<<1][0]<=mid) return findA(mid,pos<<1|1,mmm+1,R);
		else return findA(mid,pos<<1,L,mmm);
	}
	down(pos,0);
	int mmm=(L+R)>>1,tmp;
	if(l<=mmm) tmp=findA(mid,pos<<1,L,mmm);
	if(mmm<r&&(l>mmm||tmp==mmm)) tmp=findA(mid,pos<<1|1,mmm+1,R);
	return tmp;
}
inline int findB(int mid,int pos,int L,int R)//寻找mid在B中的位置
{
	if(l<=L&&R<=r)
	{
		if(treev[pos][1]<=mid) return L;
		if(L==R) return R+1;
		down(pos,1);
		int mmm=(L+R)>>1;
		if(treev[pos<<1|1][1]<=mid) return findB(mid,pos<<1,L,mmm);
		else return findB(mid,pos<<1|1,mmm+1,R);
	}
	down(pos,1);
	int mmm=(L+R)>>1,tmp;
	if(mmm<r) tmp=findB(mid,pos<<1|1,mmm+1,R);
	if(l<=mmm&&(r<=mmm||tmp==mmm+1)) tmp=findB(mid,pos<<1,L,mmm);
	return tmp;
}
signed main()
{
//	freopen("girl3.in","r",stdin);
//	freopen("girl.out","w",stdout);
	rd(n),rd(m);
	for(int i=1;i<=n;++i) ladd=radd=i,rd(addnum),add(1,0,1,n);
	for(int i=1;i<=n;++i) ladd=radd=i,rd(addnum),add(1,1,1,n);
	register int lll,rrr,mmm;
	char opt;
	for(int i=0;i<m;++i)
	{
		opt=getc();
		while(opt!='A'&&opt!='B') opt=getc();
		rd(ladd),rd(radd),rd(addnum);
		if(opt=='A') add(1,0,1,n);//插入两个线段树中
		else add(1,1,1,n);
		rd(l),rd(r);
		lll=minnum,rrr=maxnum;
		while(lll<rrr)//二分答案
		{
			mmm=(lll+rrr)>>1;
			if(findA(mmm,1,1,n)+1>=findB(mmm,1,1,n)) rrr=mmm;//他在A中的位置在B的后面说明可行
			else lll=mmm+1;
		}
		PT(lll),putc('\n');
	}
	IO::flush();
	return 0;
}

算法二:玄学的O(nlogn)做法,但是很容易被卡。

期望得分:100(随机数据,不然卡成O(n2logn));

点击查看代码
#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);//A的最大值
	node mb=B.query(1,l,r);//B的最大值
	if(ma.pos<=mb.pos) return min(ma.mx,mb.mx);//当Amax 的位置在Bmax的位置后面的情况,返回最小值
	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));
		int mn=min(ma.mx,mb.mx);
		int ss=max(solve(mb.pos+1,ma.pos-1),max(A.query(1,l,mb.pos).mx,B.query(1,ma.pos,r).mx));//递归中间部分,和两边的最最大值相比较
		return min(mn,ss);//和真个区间的最大值向比较
	}
}

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;
}

算法三:std算法,先预处理该区间每一个小区间的最大值,再二分。

期望得分:100分;

代码:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
namespace IO{
    char buf[1000010],*cur=buf+1000010;
    inline char getc(){
        (cur==buf+1000010)?fread(cur=buf,1,1000010,stdin):0;
        return *cur++;
    }
    char buff[1000010],*curr=buff;
    inline void flush(){
        fwrite(buff,1,curr-buff,stdout);
    }
    inline void putc(const char &ch){
        (curr==buff+1000010)?fwrite(curr=buff,1,1000010,stdout):0;
        *curr++=ch;
    }
   
    inline void rd(int &x){
        x=0;char ch=getc();int f=1;
        while(ch<'0'||ch>'9'){
            if(ch=='-')f=-1;
            ch=getc();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+ch-'0';
            ch=getc();
        }
        x*=f;
    }
  
    char st[60];int tp;
    void PT(int x){
        if(x==0)putc('0');
        else{
            if(x<0){
                putc('-');
                x=-x;
            }
            while(x>0){
                st[++tp]=x%10+'0';
                x/=10;
            }
        }
        while(tp)putc(st[tp--]);
    }
}
using IO::getc;
using IO::putc;
using IO::rd;
using IO::PT;

int n,q;
#define Maxn 1000010
int max1[Maxn<<2],max2[Maxn<<2],tag1[Maxn<<2],tag2[Maxn<<2];

int A[Maxn],B[Maxn];
void pushup(int k){
	max1[k]=max(max1[k<<1],max1[k<<1|1]);
	max2[k]=max(max2[k<<1],max2[k<<1|1]);
}

void make_tag(int k,int x,int y){
	max1[k]+=x;
	max2[k]+=y;
	tag1[k]+=x;
	tag2[k]+=y;
}

void pushdown(int k){
	make_tag(k<<1,tag1[k],tag2[k]);
	make_tag(k<<1|1,tag1[k],tag2[k]);
	tag1[k]=0;
	tag2[k]=0;
}

void build(int k,int l,int r){
	if(l==r){
		max1[k]=A[l];
		max2[k]=B[l];
		return ;
	}
	int mid=l+r>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	pushup(k);
	return ;
}

void update(int k,int l,int r,int ql,int qr,int val,bool ty){
	if(l>=ql&&r<=qr){
		if(ty)make_tag(k,val,0);
		else make_tag(k,0,val);
		return ;
	}
	pushdown(k);int mid=l+r>>1;
	if(qr<=mid) update(k<<1,l,mid,ql,qr,val,ty);
	else if(mid<ql) update(k<<1|1,mid+1,r,ql,qr,val,ty);
	else update(k<<1,l,mid,ql,mid,val,ty),update(k<<1|1,mid+1,r,mid+1,qr,val,ty);
	pushup(k);
	return ;
}

pair<int,int> ans[Maxn<<2];

void query(int k,int l,int r,int ql,int qr){//不同寻常的query函数 ,用来预处理每一个小区间的最大值 
	if(l>=ql&&r<=qr){
		ans[k]=make_pair(max1[k],max2[k]);//找到当前区间 
		return ;
	}
	pushdown(k);
	int mid=l+r>>1;
	if(qr<=mid){
		query(k<<1,l,mid,ql,qr);
		ans[k]=ans[k<<1];
	}else if(mid<ql){
		query(k<<1|1,mid+1,r,ql,qr);
		ans[k]=ans[k<<1|1];
	}else{
		query(k<<1,l,mid,ql,qr);
		query(k<<1|1,mid+1,r,ql,qr);
		ans[k].first=max(ans[k<<1].first,ans[k<<1|1].first);
		ans[k].second=max(ans[k<<1].second,ans[k<<1|1].second);
	}
}

int calc(int k,int l,int r,int ql,int qr){//线段树上二分 ,反回该区间上的一个分节点前后最值的最小值,分治思想 
	if(l>=ql&&r<=qr){//当前区间被包围 
		if(l==r){
			return min(max1[k],max2[k]);//找到点 
		}
		int mid=l+r>>1;
		pushdown(k);
		int s1=max1[k<<1];
		int s2=max2[k<<1|1];
		if(s1>s2){//A的最值在B的最值前面,s2一定会过但是可选择过不过s1 
			return min(s1,max(s2,calc(k<<1,l,mid,l,mid+1)));
		}else{
			return min(s2,max(s1,calc(k<<1|1,mid+1,r,mid+1,r)));//A的最值在B的最值后面。 
		}
	}
	int mid=l+r>>1;
	if(qr<=mid){
		return calc(k<<1,l,mid,ql,qr);
	}else if(mid<ql){
		return calc(k<<1|1,mid+1,r,ql,qr);
	}else{
		int s1=ans[k<<1].first;
		int s2=ans[k<<1|1].second;
		if(s1>s2){
			return min(s1,max(s2,calc(k<<1,l,mid,ql,mid)));
		}else{
			return min(s2,max(s1,calc(k<<1|1,mid+1,r,mid+1,qr)));
		}
	}
}
inline void print(int x){
	if(x<0){
		x=~x+1;
		putchar('-');
	}
	if(x>9) print(x/10);
	putchar(x%10+'0');
}
char opt[10];
int main()
{
	cin>>n>>q;
	for(int i=1;i<=n;i++){
		cin>>A[i];
	}
	for(int i=1;i<=n;i++){
		cin>>B[i];
	}
	build(1,1,n);
	int l,r,d;
	for(int i=1;i<=q;i++){
		char ch=getchar();
		while(ch!='A'&&ch!='B'){
			ch=getchar();
		}
		cin>>l>>r>>d;
		if(ch=='A'){
			update(1,1,n,l,r,d,1);
		}else{
			update(1,1,n,l,r,d,0);
		}
		cin>>l>>r;
		query(1,1,n,l,r);
		print(calc(1,1,n,l,r));
		putchar('\n');
	}
	return 0;
}

后面的题都不会了,我太蒟蒻了QWQ.

posted @   SSZX_loser_lcy  阅读(46)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示