2023NOIP A层联测30 草莓列车

题目大意

给定一个序列 a i a_i ai,有 m m m次操作,形如l r v,表示将 [ l , r ] [l,r] [l,r]的每个 a i a_i ai变为 max ⁡ ( a i , v ) \max(a_i,v) max(ai,v)。求最终的序列。

为了避免过量的输入,此题使用特殊的读入格式。

第一行有三个整数 n , m , t y p e n,m,type n,m,type,其中 t y p e type type表示数据类型。

t y p e = 1 type=1 type=1时,每次操作的区间都满足左端点 l = 1 l=1 l=1

第二行有 n n n个数,表示初始序列。

第三行有两个数 x 0 , s e e d x_0,seed x0,seed,使用示例如下:

namespace Maker{
	unsigned int x0,seed;
	void init(){scanf("%u%u",&x0,&seed);}
	inline unsigned int getnum(){
		x0=(x0<<3)^x0;
		x0=((x0>>5)+seed)^x0;
		return x0;
	}
}
int n,m,typ;
int main(){
	scanf("%d%d%d",&n,&m,&typ);
	// input n numbers as a[1...n]
	Maker::init();
	for(int i=1; i<=m; ++i){
		int l=Maker::getnum()%n+1,r=Maker::getnum()%n+1;
		unsigned int v=Maker::getnum();
		if(l>r) swap(l,r);
		if(typ==1) l=1;
 		// do something
 	}
	// output n numbers of a[1...n]
}

数据范围

1 ≤ n ≤ 1 0 5 , 1 ≤ m ≤ 1 0 7 1\leq n\leq 10^5,1\leq m\leq 10^7 1n105,1m107


题解

对于每次操作l r v,我们将 r r r v v v存储在维护区间左端点 l l l v e c t o r vector vector中。

然后,从左到右枚举左端点 i i i。对于每个以 i i i为左端点的操作,设这个操作的右端点为 r r r,权值为 v v v,则将 r r r及其左边的部分全部对 v v v max ⁡ \max max,然后查询位置 i i i的值。这里涉及区间修改和单点查询。

区间修改的次数为 O ( m ) O(m) O(m),单点查询的次数为 O ( n ) O(n) O(n),用线段树的话是 O ( ( m + n ) log ⁡ n ) O((m+n)\log n) O((m+n)logn),会 TLE \text{TLE} TLE。下面考虑优化。

因为区间修改的次数比单点查询的次数大很多,而且区间修改的速度肯定不快于单点查询,所以我们可以将区间修改变成对 r r r的单点修改,将单点查询变成查询 i i i n n n的最大值,那么现在要求的操作就是单点修改和区间查询。

考虑分块,单点修改是 O ( 1 ) O(1) O(1)的,区间查询是 O ( n ) O(\sqrt n) O(n )的,那么总时间复杂度为 O ( m + n n ) O(m+n\sqrt n) O(m+nn ),是可以过的。

code

#include
using namespace std;
namespace Maker{
	unsigned int x0,seed;
	void init(){scanf("%u%u",&x0,&seed);}
	inline unsigned int getnum(){
		x0=(x0<<3)^x0;
		x0=((x0>>5)+seed)^x0;
		return x0;
	}
}
const int N=100000,B=350;
int n,m,typ,bl;
unsigned int a[N+5],w[N+5],tw[B+5];
struct node{
	int x;
	unsigned int v;
};
vector<node>p[N+5];
int pos(int i){
	return (i-1)/bl+1;
}
void ch(int x,unsigned int v){
	w[x]=max(w[x],v);
	tw[pos(x)]=max(tw[pos(x)],v);
}
unsigned int find(int l,int r){
	int vl=pos(l),vr=pos(r);
	unsigned int re=0;
	if(vl==vr){
		for(int i=l;i<=r;i++) re=max(re,w[i]);
		return re;
	}
	for(int i=l;i<=vl*bl;i++) re=max(re,w[i]);
	for(int i=vl+1;i<=vr-1;i++) re=max(re,tw[i]);
	for(int i=vr*bl-bl+1;i<=r;i++) re=max(re,w[i]);
	return re;
}
int main()
{
//	freopen("train.in","r",stdin);
//	freopen("train.out","w",stdout);
	scanf("%d%d%d",&n,&m,&typ);bl=sqrt(n);
	for(int i=1;i<=n;i++) scanf("%u",&a[i]);
	Maker::init();
	for(int i=1;i<=m;++i){
		int l=Maker::getnum()%n+1,r=Maker::getnum()%n+1;
		unsigned int v=Maker::getnum();
		if(l>r) swap(l,r);
		if(typ==1) l=1;
		p[l].push_back((node){r,v});
	}
	for(int i=1;i<=n;i++){
		for(node j:p[i]) ch(j.x,j.v);
		a[i]=max(a[i],find(i,n));
		printf("%u ",a[i]);
	}
	return 0;
}

你可能感兴趣的:(题解,题解,c++)