给定一个序列 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 1≤n≤105,1≤m≤107
对于每次操作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),是可以过的。
#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;
}